たまにはアニメの話も書こうと思う.
2018年のアニメを適当に振り返る. 最後に積み残しがあるので,来年以降暇なタイミングで見ていきたい.
続きを読むこの記事は ex-crowdworks Advent Calendar 2018 の21日目です.
CrowdWorksを退職して8ヶ月くらいが経った.
CrowdWorksにいたときはSREをしていたので,テレビ放映があるときには少し覚悟が必要だったんだけど,その話をしようと思う.
あと,ここで書く話は,ただの昔話 であり,現在ではテレビが突然来ても割と耐えられるくらいの状態にはなっていると思う.ので,こんなことをしなくても凌げると期待している.
基本的にCrowdWorksは,クラウドソーシングのサービスなので,ニュースサイトやゲームのサービスほど,普段から大量の接続をさばく必要はない. そのため,そういう人たちにとっては物足りないくらいの対策でしかないと思うことを断っておく.
続きを読むこの記事は scouty Advent Calendar 2018 の17日目です.
fluentdに関して,勢い余って今年こういう発表をした.
完全に酔っていたので勢いだけなのだが,その後マトモなfluentdクラスタができたので書こうと思う.
もう二度とchefで作ろうとは思うまい.
続きを読むこの記事は Mastodon Advent Calendar 2018 の10日目です.
普段はMastodonのデスクトップ向けクライアントWhalebird を開発しています.
あと,Pleromaのインスタンスを運用してます.全然人が少ないし特に何も運営らしきことはしていないんだけど.
というわけで今日はマストドンクライアントの話です. Whalebirdの実装の中でも,結構重かった(いろんな意味で)部分の話をします.
WhalebirdはElectronベースのMastodonクライアントですが,ただWebページを表示するだけのガワアプリではなく,フロントを全部自前実装してAPIを叩いているアプリです. そのため,前提として,Mastodon本体のフロントエンドの資産はほぼ使えません.
また基本的にAPIが用意されていない機能も使うことができません. そのため,これから書くような「Webの再実装に近いんだけど,全部自分で作らないといけない」状態になってます.
Whalebirdには
のサジェスト機能があります.
これらのサジェストを実装していく上で,考慮点がいくつかありました.
こういうのに迷ったときにはMastodonのWebを参考にするんですが,Webでは
という実装でした. というわけで,Whalebirdでも検索は都度APIを叩くことにしました. ただ,流石にサードパーティー製のアプリケーションで,APIコールしまくるのはどうかと思ったので.キー入力イベントは間引きならがAPIを叩いています.
そのため,基本的にここの部分の速さはインターネットの速度によって制限されます.まぁPC向けなのでそこまで遅い環境で使われることは想定しなくていいかなと思ってます.
キー入力イベントを間引いたとしても,キー入力のたびに
という処理が裏で走るので,ここはかなりCPUを食う場所です.
2.5.0あたりでやたら入力がもっさりしたバージョンをリリースしましたが,あれの原因はほぼこいつらでした.
あそこで,汚かった実装をいろいろとリファクタリングして,現状はこんな感じ.
const textAtCursorMatch = (str, cursorPosition, separators = ['@', '#', ':']) => { let word let left = str.slice(0, cursorPosition).search(/\S+$/) let right = str.slice(cursorPosition).search(/\s/) if (right < 0) { word = str.slice(left) } else { word = str.slice(left, right + cursorPosition) } if (!word || word.trim().length < 3 || separators.indexOf(word[0]) === -1) { return [null, null] } word = word.trim().toLowerCase() if (word.length > 0) { return [left + 1, word] } else { return [null, null] } } export default textAtCursorMatch
ここは本家のソースをだいぶ参考にしました.
で,現状は普通に使っててストレスないくらいにはなっていますが,やはり多少CPUは使いますね…….
もう一つ2.5.0で重くなった要因があります. それが,EmojiMartの絵文字パレットの追加です.
これはMastodon本家に合わせて,EmojiMartのvue版を使っていました.
ただ,こいつのロードになかなか時間がかかるため, v-show
で制御していました.これが重くなる原因で,この重さのコンポーネントを常に裏側に用意しておくと,またメモリを500MB以上食うようになりました.
というわけで最近こいつは v-if
で制御するようにしています.
そうすると絵文字パレットの表示には時間がかかるんですけどね…….
Whalebirdのトゥートにはパーサが仕込まれています. これは,クリック時に以下の判定を行い,それぞれの動作に遷移させるために必要な処理です.
また,これに関してはweb側の実装が一切参考にできません(Reactなので,おそらくパースなんかしなくてもRouterさえちゃんと設定してあれば画面遷移できるので).
というわけで,
export function findAccount (target, parentClass = 'toot') { if (target.getAttribute('class') && target.getAttribute('class').includes('u-url')) { return parseMastodonAccount(target.href) } // In Pleroma, link does not have class. // So we have to check URL. if (target.href && target.href.match(/^https:\/\/[a-zA-Z0-9-.]+\/@[a-zA-Z0-9-_.]+/)) { return parseMastodonAccount(target.href) } // Toot URL of Pleroma does not contain @. if (target.href && target.href.match(/^https:\/\/[a-zA-Z0-9-.]+\/users\/[a-zA-Z0-9-_.]+/)) { return parsePleromaAccount(target.href) } if (target.parentNode === undefined || target.parentNode === null) { return null } if (target.parentNode.getAttribute('class') === parentClass) { return null } return findAccount(target.parentNode, parentClass) } export function parseMastodonAccount (accountURL) { const res = accountURL.match(/^https:\/\/([a-zA-Z0-9-.]+)\/(@[a-zA-Z0-9-_.]+)/) const domainName = res[1] const accountName = res[2] return { username: accountName, acct: `${accountName}@${domainName}` } } export function parsePleromaAccount (accountURL) { const res = accountURL.match(/^https:\/\/([a-zA-Z0-9-.]+)\/users\/([a-zA-Z0-9-_.]+)/) const domainName = res[1] const accountName = res[2] return { username: `@${accountName}`, acct: `@${accountName}@${domainName}` } }
こういうややこしいパーサをいくつか書いています.
リンクを外部ブラウザで開くだけなら,そこまで苦労するものでもないんですが,その手前にハッシュタグとアカウントのパーサを挟もうと思うと,これしかありませんでした.
こいつが重い要因は,要素の親を再帰的に辿るからです. これには理由があって,MastodonのAPIが返してくるstatusはhtml構造となっており,
<p> <span> <a href="https://social.mikutter.hachune.net/@h3_poteto"> @<span>h3_poteto</span> </a> </span> hogehoge </p>
こんな感じで,必ずしもクリックした要素が<a>
タグになっているわけではないからです.
また,MastodonとPleromaでこのhtml構造が微妙に違う場合があって,それらの差異もこのパーサですべて吸収しています.
めちゃくちゃフロントの話になってしまいましたが,そのくらいバックエンドでボトルネックになるところは少ないです. 今のところMastodonのAPIはよくできているので,裏側でストリーミング更新したりする部分は,ほとんど重くならずに実装できています.
実は最近の更新で,裏でストリーミングするタイムラインを選べるようになっているんだけど,そこでストリーミング数を増やしても,メモリ消費的にはそこまで上がりません. CPUは少し食うかもしれない,それはWebSocketなので仕方がないのだけれど…….
というわけで,実装的にも動作的にも重い部分を紹介しました. この辺はできればもっとスマートに高速化していきたいとは思っているので,今後にご期待ください.
この記事はscouty Advent Calendar 2018 の3日目です.
ECSで動かしているサービスのスケジュールジョブが多くなってきた. もともとECS Scheduled Taskを使っていたんだけど,数十個レベルになってくると,これで管理するのはだいぶつらい.
というわけでRundeckを構築したメモ.
続きを読む