Featured image of post コードディスパッチャー【Parallel Run】「同じかどうかは、こちらが決めます」〜提供終了の通告が来た夜に〜

コードディスパッチャー【Parallel Run】「同じかどうかは、こちらが決めます」〜提供終了の通告が来た夜に〜

提供終了の通告で乗り換えが必要なのに動いているものを止められない問題を、新旧並走と通す割合の段階移行(Parallel Run)で解決し、標準ライブラリだけで実装し確かめます。

第1幕: 持ち込み ── ご報告というか、確認というか

先月分の綴じ込みを棚へ戻したところだった。指を離すと、紙とインクの匂いが少しだけ残った。棚の高いところは埃を払ったばかりで、背表紙の文字が揃って見える。私は自分の席に戻り、今夜の記録帳を開いた。

サカキは表示盤の前にいた。琥珀色の光が、盤の下の縁に沿って一定の間隔で流れている。今夜はどの系統にも遅れが出ていない。

ドアが開いた。押し方に急ぎがなく、かといって遠慮でもない。用件を先に決めてきた人の開け方だった。

「こんばんは」

フクハラさんだった。半年前に一度、別件でここへ来たことがある。人事部で就業規程の運用を担当している人で、そのときも同じように、静かに入ってきた。

「……ご報告というか、確認というか、そういう用件で来ました」

サカキは表示盤から目を離し、椅子を勧めた。用件の言い方を訂正しなかった。

私は記録帳の頭に「報告」と書いた。いつもは「来訪」と書く欄だった。その下の欄には、まだ何も書けなかった。

フクハラさんは鞄から紙を出した。二度畳んで開いた跡が、紙に残っている。

「今、規程の問い合わせに自動で答える仕組みを使っているんですが」

「それが、来期で使えなくなります。向こうから通知が来ました」

紙を机に置く。他社線からの通知だった。日付が入っている。この日を過ぎたら、今の直通は取りやめになると書いてある。

「移すしかないのは分かっています。でも、止められないんです。毎日、朝から問い合わせが来るので。一日に百件くらいです。止めたら、その百件がそのまま人事に来ます。うちは三人しかいません」

「期限が来たら、いったん止めますと、上には報告するつもりです」

一息だった。結論から先に言う人だ、と私は思った。前に来たときも、そうだった。

サカキはすぐには答えず、通知の日付だけを見ていた。

「試されましたか。新しいほうは」

「一応」

フクハラさんは二枚目の紙を出した。左に旧いほうの答え、右に新しいほうの答え。同じ質問が五件、並べて印刷してある。

「同じことを訊いて、並べてみたんです。……でも、同じなのか、違うのか、私には分からなくて」

そこで初めて、声の調子が少し落ちた。

「私は規程の担当ですけど、この仕組みを作った人間ではないので、どこを見れば『同じ』と言えるのかが分からなくて」

私は書き取った。この人は、諦める前に、やることをやっていた。

サカキは規模だけを確かめた。期限までは二か月と少しあること。答える相手が全員社員であること。三年前に外の業者へ頼んで組んでもらったもので、担当した人はもういないこと。

それだけ聞いて、原因の話には入らなかった。

「その紙、こちらへ回してください」

フクハラさんが紙を滑らせる。サカキは受け取ってから、机の上でまっすぐに置き直した。

フクハラさんは、壊れたものを持ってきたのではなかった。判定できなかった、という経験を持ってきていた。

第2幕: 照合 ── 同じかどうかは、こちらが決めます

サカキは、今動いている仕組みのコードを開くように頼んだ。フクハラさんが手元の端末を操作し、画面を指令所の盤へ映す。短いコードだった。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
from dataclasses import dataclass
from typing import Protocol


@dataclass(frozen=True)
class Answer:
    text: str
    article: str


class Responder(Protocol):
    async def answer(self, question: str) -> Answer: ...


@dataclass(frozen=True)
class Window:
    client: Responder

    async def ask(self, user_id: str, question: str) -> Answer:
        return await self.client.answer(question)

「答えは、二つに分かれて返ってきていますね」とサカキが言った。「本文と、引いた規程の番号」

「はい。番号は画面にも出しています。社員が自分で規程を確認できるように」

サカキはコードの一行を指した。窓口が持っている直通先は、一つだけだった。この一本が、外の会社のモデルにつながっている。窓口は、誰から来た問い合わせかを受け取ってはいる。受け取ったまま、どこにも使っていない。

「直通先が一つです。替えるなら、この一行を書き換えて、その日から全員を新しいほうへ回すことになります」

「そう思っていました。切替の日を決めて、その日に入れ替えるんだと」

「戻すときも、全員まとめてです」

一度に全部動かす、ということは、間違えたときも全部まとめて間違える、ということだった。私はそう書いた。

フクハラさんの背が、椅子の背もたれに触れた。「……そうなんですよね。だから、怖くて」

サカキは責める調子を出さなかった。

「三年前にこの形で組んだのは、おかしくありません。替える予定がないものを、替えられる形にしておく理由は、当時ありませんでしたから」

そして、机の上の紙を引き寄せた。

「持ってこられた紙を、一件ずつ見ましょう。同じかどうか、フクハラさんが判定してください」

フクハラさんが一件目に目を落とす。有給休暇の繰り越しについての問い合わせだった。左は「繰り越せるのは20日までです。」、右は「繰り越せる日数は20日が上限です。」どちらも第32条を引いている。

「これは、同じです」

即答だった。

二件目。育児短時間勤務の質問。左は「子が3歳に達するまで利用できます。」、右は「お子さまが3歳になるまでご利用いただけます。」

フクハラさんの指が、紙の上で止まった。行を二度たどってから、顔を上げないまま言った。

「……これは、どうなんでしょう。言っていることは、たぶん同じなんですけど、書き方が全然違って。うちの社内文書は、こんなに丁寧な言い方はしないので」

私はその間を書き取った。声が止まっていたのは数秒だった。

サカキは急かさなかった。「三件目を見てください」

三件目は通勤手当の上限額だった。左は「上限は月額30,000円です。」で第18条。右は「通勤手当の上限は月額30,000円です。」で第19条。

「あ……これ、番号が違います」

フクハラさんが紙を持ち上げた。

「金額は同じですね。でも、引いている条文が違う。……こっちのほうが、正しいかもしれません。去年の改定で、通勤手当の条が移っているので」

サカキが口を開いた。

「今、三通りの決め方が出ました」

フクハラさんが顔を上げる。

「一件目は、書いてあることが同じかどうかで決めました。二件目は、書き方が違うので止まりました。三件目は、どちらが正しいかで決めようとしています」

「……ああ」

「どれも、決め方としては筋が通っています。ただ、それが混ざっているうちは、日に百件届くものを同じ基準で判定することはできません」

フクハラさんはしばらく黙っていた。それから、諦めたときとは違う顔で言った。

「じゃあ、どうやって判定すればいいんですか」

「同じかどうかは、こちらが決めます」

サカキは紙をまっすぐに戻した。

「返ってくるものを、変わっていい部分と、変わっては困る部分に分けます。先に分けておきます。ここでは、文面は変わっていい。引く規程の番号は、変わっては困る」

「文章が良くなっているかどうかは、判定に入らないんですか」

「見ません。見ないと決めます」

フクハラさんが黙る。納得していないときの黙り方だった。

サカキは続けた。

「文章の似ている度合いを機械で測る方法はあります。ただ、あれは『〜である』と『〜ではない』の差でも、その数値が高く出ます。逆の意味を、同じだと判定することがある」

「別のモデルに、同じ意味かどうかを採点させる方法もあります。こちらは、採点する側の答えも毎回変わります。判定の道具が毎回違う答えを返すなら、判定になりません」

「今夜採る決め方は、何度やっても同じ結果になります。番号が一致しているか、していないか。それだけです」

フクハラさんが小さくうなずいた。「……そこだけなら、私にも分かります」

サカキは私に、シミュレータを用意するよう言った。フクハラさんが持ってきた五件の過去の答えを、そのまま突き合わせの元として置く。今動いている窓口の直通先だけを新しいほうに差し替えて、同じ五件を流す。

流す前に、サカキがフクハラさんに確認した。

「引く規程の番号が、今までと変わったもの。今夜は、それを拾います」

「異常と呼ぶかどうかは、後で決めます。まず、拾えるようにします」

「ほかは、まだ決めません。回答の文面が変わることは、今夜は拾いません」

「はい」

流した。五件のうち一件、番号が変わっていた。三件目の通勤手当だった。警報が鳴った。

フクハラさんが少し前に出た。

「……ちゃんと、見つかるんですね」

「見つかったのは、フクハラさんが紙を持ってきたからです」

サカキは盤の表示を指さなかった。指したのは、机の上の紙だった。

「今の仕組みの中には、突き合わせる相手がどこにもありません」

「それに、今流したのは、持ってきた五件だけです。本番の問い合わせは、この間も一件もここを通っていません」

サカキは机の紙を指した。

「この警報は、指令所の机の上で鳴っています。路線の上ではありません」

第3幕: 指令の一手 ── 客を乗せない試運転

「止めずに移す方法が、あるんですか」

フクハラさんの声に、来たときとは違う張りがあった。

「あります」とサカキが言った。「さっき、この机の上でやったことを、毎日の百件の中に置きます」

「新しいほうにも、同じ質問を流します。ただし、利用者に返すのは、今までの答えだけです。新しいほうの答えは、記録に取るだけで、誰にも届きません」

サカキは説明をそこで止め、机の紙をもう一度見た。

「客を乗せない試運転です。同じ区間を、同じ時刻に走らせて、どう走ったかだけを記録します」

サカキは新しいコードを盤に出した。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import asyncio
import hashlib
from dataclasses import dataclass
from typing import Protocol


class Recorder(Protocol):
    def record(self, user_id: str, question: str, old: Answer, new: Answer) -> None: ...


def same_decision(old: Answer, new: Answer) -> bool:
    return old.article == new.article


def bucket_of(user_id: str, migration: str) -> int:
    digest = hashlib.sha256(f"{user_id}:{migration}".encode()).hexdigest()
    return int(digest[:8], 16) % 100


@dataclass(frozen=True)
class MigrationWindow:
    old: Responder
    new: Responder
    percent: int
    recorder: Recorder
    migration: str

    async def ask(self, user_id: str, question: str) -> Answer:
        old_answer, new_answer = await asyncio.gather(
            self.old.answer(question),
            self.new.answer(question),
        )
        if not same_decision(old_answer, new_answer):
            self.recorder.record(user_id, question, old_answer, new_answer)
        if bucket_of(user_id, self.migration) < self.percent:
            return new_answer
        return old_answer

「新しいほうへ通す割合を、数字で持ちます。今は0です」

サカキが percent の行を指した。

「0のあいだも、新しいほうへは同じ質問が流れます。答えが誰にも届かないだけです。10にすれば、十人に一人が新しいほうの答えを受け取ります。100にすれば全員です」

フクハラさんが画面を見たまま言った。

「じゃあ、試運転と、切替は、別の仕組みではなくて」

「同じ目盛りの、両端です」

サカキは、比喩の前の言い方へ戻した。

「切替の日に書き換えるコードは、別にありません。この数字が0か100かの違いだけです」

「新旧を並べて走らせて、返すほうだけを少しずつ移していく。Parallel Run と呼ばれる進め方です」

私はその言い方を書き写した。試運転という言葉と切替という言葉は、私の記録の中ではずっと別の欄に置かれていた。それが一本の目盛りの両端だという言い方は、今夜が初めてだった。

別の欄に置いていた二つを、私は一つの欄へ描き直した。左端に0、右端に100。その間に、途中がある。

目盛り0・10・100の三つの状態。0では新しいほうの答えが誰にも届かず食い違いだけが記録に残り、10では十人に一人へ届き、100では全員に届いて旧いほうが届かなくなる

描いてみると、左端と右端で違っているのは、届かないほうが新旧どちらかというだけだった。真ん中では、その届かない線が消えて、二本に割れる。

「途中で、おかしいと分かったら」

「目盛りを0に戻します。日を決め直さなくても戻せます」

サカキは目盛りの行を指したままだった。

「それと、目盛りが10のあいだに起きることは、十人に一人にしか起きません。全員に起きてから気づくのとは、後始末の大きさが違います」

フクハラさんが、初めて紙から顔を上げたまま黙った。それから小さく息を吐いた。

「一斉に替えるのが怖かったのは、そこでした」

「一つ、気になることがあるんですが。利用者から見て、返事は今より遅くなりますか」

サカキが asyncio.gather の行を指した。ここは私にも読めた。二つの問い合わせを同時に投げて、両方が揃うのを待ってから先へ進む書き方だ。

「はい。両方の答えが揃うまで待ちます」

サカキは言い直しをしなかった。

「待たなければ、記録が取れるときと取れないときが出ます。取れたり取れなかったりする記録は、後から見たときに何も言えません」

「待つ分だけ、遅いほうに引きずられます。それが、確かめるための代償です」

フクハラさんが少し考えてから言った。「……一日待つわけではないので、そこは飲めます」

サカキは次に、コードの中ほどを指した。bucket_of という短い関数だった。

「ここに、一つだけ、わたしには決められないことがあります」

フクハラさんが顔を上げる。

「同じ人が、訊くたびに違うほうへ行っていいですか」

「……」

「行っていいなら、呼ばれるたびにその場で決めれば済みます。行ってはいけないなら、その人ごとに決めます。どちらが良いかは、規程の問い合わせがどう使われているかで決まります。それは、わたしよりフクハラさんのほうがご存じです」

フクハラさんは、今度は迷わなかった。

「よくないと思います。同じ人が、期の変わり目に何度も同じことを訊いてくるので。前に訊いたときと答え方が変わると、混乱します。うちの社員は、そこを気にします」

「では、その人の識別子で決めます。同じ人は、いつも同じほうです」

サカキが比喩を足したのは、そのあとだった。

「同じ定期券の客は、いつも同じ経路になります」

「……その決め方は、毎回同じ答えになるんですか」

「なります。同じ入力からは、いつ計算しても同じ値が出る道具を使っています。hashlib ──入力から決まった値を作る、Python に最初から入っている道具です」

サカキは bucket_of の中身を指した。

「利用者の番号と、この移行の名前をつないで、この道具に通します。出てくるのは長い十六進の文字列なので、頭のところだけを数字に直します。それを100で割った余りを取ると、0から99までのどれかになります。その数字が、目盛りより小さければ新しいほうです」

「入力が少し違うだけで、出てくる値は大きく散ります。だから0から99のあいだに、だいたい同じ数ずつ分かれます。十人に一人、という言い方ができるのはそのためです」

「Python には hash() という、もっと手軽な仕組みも最初から入っています。ただし文字列を渡したときは、プログラムを起動し直すと、同じ文字列でも別の値になります。それを使うと、再起動のたびに全員の行き先が入れ替わります」

「移行の名前を混ぜているのは、次に別のものを移すときのためです。名前が変われば並びも変わります。同じ人が、いつも先頭に立たされることはありません」

同じ人がいつも同じほうへ行く、という約束は、使う道具の性質そのものに支えられていた。私はそう書き留めた。

フクハラさんの質問は、まだ続いた。

「割合を上げていく途中で、一度新しいほうへ行った人が、また元に戻ることはありませんか」

「ありません」

サカキは bucket_of の引数を指した。

「この関数は、目盛りを受け取っていません。人の側の数字は、最初から最後まで動きません。動かしているのは目盛りだけです。0から10へ上げれば、条件に当てはまる人が増えるだけで、当てはまっていた人が外れることはありません」

最後に、組み立てのところを見せた。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
def build_window(
    old: Responder,
    new: Responder,
    *,
    percent: int,
    recorder: Recorder,
    migration: str,
) -> MigrationWindow:
    return MigrationWindow(
        old=old,
        new=new,
        percent=percent,
        recorder=recorder,
        migration=migration,
    )

「問い合わせを受ける側のコードは変わりません。ここで、直通先を二つと、目盛りと、記録の置き場所を渡すだけです」

「これができるのは、外へ問い合わせる場所が一箇所にまとまっていたからです。三年前に組んだ人が、そこだけは分けてくれていました」

「ただ、目盛りを動かすのは誰かの仕事です。仕組みを入れたから自動で進む、ということはありません」

「目盛りは、ここで渡す数字です。動かすには、数字を変えて入れ替えます。入れ替えている最中は、台によって目盛りが違う時間ができます」

フクハラさんがうなずいた。「そこは、私がやります」

サカキは最後に一つ、範囲を切った。

「この振り分けは、動かす台が何台に増えても、同じ人は同じほうへ行きます。計算に外の道具を使っていないからです」

「ただし、記録のほうは違います。差分は、動いている台の中に溜まります。台が増えれば、記録は台の数だけ散ります。集めるなら、集める場所を別に決めてください」

私はその二つを別の行に書いた。同じ仕組みの中で、片方は台数に関係がなく、もう片方は台数の話になる。混ぜて書くと、後から読む人が取り違える。

第4幕: シミュレータと引き渡し ── 外す日を決める

サカキが、同じ五件の台本をもう一度シミュレータへ通した。今度は組み直した窓口で、目盛りは0のままにしてある。

結果を声に出すのは、記録を書く側の仕事になっている。

五件とも、届いた答えは今までと同じだった。有給休暇も、育児短時間勤務も、通勤手当も、慶弔休暇も、副業の届出も、旧いほうの文面がそのまま返っている。

そして記録のほうに、一件だけ残っていた。通勤手当の問い合わせで、旧いほうが第18条、新しいほうが第19条。どちらの答えも、文面ごとそのまま並べて残っている。

「届いているものは、何も変わっていません」とサカキが言った。「変わったのは、変わったことに気づける場所が、経路の中にできたことです」

フクハラさんが記録の行を指した。「これ、私が紙でやっていたことですよね」

「同じことです。置き場所が、机の上から路線の上へ移りました」

サカキは続けて、目盛りを10に上げて流し直した。

社員番号 E-1001 の問い合わせに、新しいほうの答えが届いた。E-1018 には、旧いほうの答えが届いた。

「この二人は、何が違うんですか」

「社員番号から計算した値が違います。E-1001 は3、E-1018 は12です。今の目盛りが10なので、3は内側、12は外側です」

「目盛りを12に上げたら、E-1018 は移りますか」

「移りません。E-1018 の12は、目盛りの12より小さくないからです。13以上にして初めて移ります」

私は二つの社員番号を、計算した値のところで並べて書いた。人の側の数字と、目盛りの数字は、別の列に置いた。

社員番号と移行の名前をhashlibに通して得た値は利用者ごとに固定され、動くのは目盛りの側だけであることを示す図

並べてみると、動いているのは目盛りの列だけだった。人の側の列は、最初から最後まで同じ数字のまま置かれている。

サカキは同じ社員番号で三度続けて流した。三度とも、同じほうへ行った。

三度とも同じ側だった。乱数も、時計も、渡していない。渡していないのに、答えは決まっていた。私は前の回のことを思い出しながら、そう書いた。

サカキが一言だけ足した。

「毎回同じ結果になるものは、確かめるのが楽です」

それから、目盛りを100にして流し、最後にもう一度、別の窓口で流した。新しい直通先だけを持つ窓口──最初に見せてもらったのと同じ形のコードで、中身の直通先だけが新しくなっている。

答えは、目盛り100のときとまったく同じだった。

フクハラさんが画面を見て言った。

「これ、最初の形と同じですね」

「はい。替えられる形にしておく仕事は、替え終われば要らなくなります」

シミュレータの結果は五本、〇・〇二五秒だった。目盛りが0のとき届く答えが今までと変わらないこと、番号が変わった一件が記録に残ること、目盛りを上げるとその人にだけ新しいほうが届くこと、同じ人を三度呼んでも三度とも同じほうへ行くこと、そして旧いほうを外しても答えが変わらないこと。その五つを確かめた。

サカキは、そこで区切りを入れた。

「保証することを言います。目盛りが0のあいだ、届く答えは今までと同じです。番号が変わった件は、必ず記録に残ります。同じ人は、いつも同じほうへ行きます」

「保証しないことを言います」

「まず、費用です。並走しているあいだは、新しいほうにも同じ問い合わせが流れます。両方に課金されます。安いほうへ移るなら、二つ足しても今より安くなることがありますし、高いほうへ移るなら今より高くなります。どちらになるかは、単価を見てください」

「待ち時間は、遅いほうに引きずられます。さっき申し上げたとおりです」

「それから、この仕組みが判定しているのは、正しさではありません。変わったかどうかです。新しいほうと旧いほうが、同じように間違っていれば、一致していると判定します」

フクハラさんが顔を上げた。「……それは、拾えないんですね」

「拾えません。今夜の判定は、番号が変わったかどうかしか見ていません。文面が悪くなっていても、番号が同じなら通ります」

「文面は見ないと決めましたから、そこは私たちが別に見ます」

フクハラさんは、もう確認の口調ではなかった。サカキはうなずいてから、言い足した。

「拾う相手を、直通先を替えることで新しく出てくる違いだけに絞りました。元から間違っていたものは、替えなくても間違っています。それは今夜の移行とは別の日の仕事です」

「機械が決めるのは、変わったかどうかまでです。どちらが正しいかは、残った記録を人が読んで決めます。さっきの通勤手当も、機械は違うとしか言っていません。第19条のほうが正しいと言ったのは、フクハラさんです」

「目盛りを動かすときの入れ替えも、一瞬では終わりません。入れ替えている間は、台によって目盛りが違います。上げる方向にしか動かさないので、行き先が前後することはありませんが、割合はしばらく揺れます」

「もう一つ。さっき申し上げたとおり、外へ問い合わせる場所が一箇所だったので、そこへ目盛りを差せました。呼び出しが何箇所にも散らばっている仕組みでは、差す場所を作るところから始まります。それは今夜の話の外です」

「それから、今夜は比べる軸が最初からありました。規程の番号です。答えが文章だけで返ってくる仕組みなら、何を軸にするかを決めて、それを形のある項目として返させる。そこが最初の一手になります」

フクハラさんは、しばらく紙を見ていた。それから通知書のほうを手に取った。

「期限は、向こうが決めています」

顔を上げた。

「でも、外す日は、こちらで決められますね」

「決められます」

「来月の頭から、目盛りを1にします。それで一週間、記録を見ます。何も出なければ、10に上げます」

「そこから先は、差分が出なかった週の翌週に一段ずつ上げます。100にして一週間、記録が空のままなら、旧いほうを外します」

サカキが一つだけ訊いた。

「差分が出たとき、どこまでを許すかは、決まっていますか」

フクハラさんは、少し黙った。

「……そこは、まだです。持ち帰ります。条文の番号が変わるのは、去年の改定があったので、たぶん出ます。どこまでを直っていると見るかは、私だけでは決められないので、上と決めます」

「それで足ります」

フクハラさんは紙を鞄にしまい、立ち上がった。

「ありがとうございました。止めますと言いに来たのに、始める日を決めて帰ることになりました」

廊下のほうで、足音が一度止まり、それから遠くなった。表示盤の琥珀色は、来たときと変わらない間隔で流れていた。

私は記録の残りの欄を埋め始めた。打った一手、配線した場所、保証しないこと。書くことはいつもどおりの分量だった。

サカキが、盤から目を離さずに言った。

「トウヤ。この指令所、来期で畳みます」

私はペンを止めなかった。止めずに、続きを聞いた。

「統合先の指令所があります。あちらへ機能を移します。わたしも、あなたも、そちらへ移ります」

「あなたが書いてきた記録は、向こうへ渡します。引き継ぎの資料です。八年分あります。初日から使える形で残っているものは、ほかにありません」

私は書いていた行を書き終えてから、顔を上げた。

「相談を受ける場所は、なくなりません。移るだけです」

サカキはそこで初めて、こちらを見た。

「今日、決まりました。決まったので、言いました。決まっていないことは、当直に流しません」

私が訊いたのは一つだけだった。記録の様式は、向こうのものに合わせるのか。

「合わせます。というより、こちらの様式が向こうのものです。少しずつ、そうしてきました」

それだけだった。サカキは表示盤に向き直り、翌日のダイヤを一本ずつ確かめ始めた。

向こうが期限を決めて、こちらが移り方を決める。さっき、この机の上でやったことと同じだった。

「止まらない方法じゃない。止まり方を決めるんです」

私は様式の欄をすべて埋めた。来訪。申告された症状。今のダイヤの問題。打った一手。配線した場所。保証しないこと。シミュレータ結果。次の当直への申し送り。

全部埋めてから、様式に無い余白へ、一行だけ書き足した。

「本日、目盛りは0。まだ誰にも届いていない」


🚦 本日の指令記録(Dispatch Log)

  • 指令の定石(パターン名): Parallel Run(新旧並走)── 新しいほうにも同じ入力を流しながら、届ける側を割合で少しずつ移し、最後に旧いほうを外す進め方
  • 申告された症状: 「新しいほうを試したが、同じなのか違うのか判定できない」。本当に手が止まっていたのは判定の作業ではなく、同じと呼ぶ基準が誰の手にも無かったこと。持ち込まれたときには既に、期限が来たら止めるという結論が出ていた
  • 今のダイヤの問題: 窓口が直通先を一つしか持っておらず、替えるには切替の日に全員をまとめて移すしかなかった。三年前は替える相手がいなかったのだから、その形で用は足りていた
  • 打った一手: 新旧の両方へ同じ質問を流し、届けるほうを割合で決めた。判定は引く規程の番号の一致だけで行い、文面は見ない。同じ人はいつも同じほうへ行く。並走と切替を別の仕組みにせず、一本の目盛りの両端として扱った
  • 配線した場所: 起動時の組み立て(build_window)。直通先を二つと、目盛りと、記録の置き場所を渡している。問い合わせを受ける側のコードは変えていないが、目盛りを動かす仕事は誰かに残っている
  • 保証しないこと: 並走中は両方に課金される(単価が違うため、二つ足した額が今より高いか安いかは移り先による)。待ち時間は遅いほうに引きずられる。判定しているのは正しさではなく変化の有無であり、新旧が同じように間違っていれば一致と判定する。文面の劣化は見ていない。今回は比べる軸(規程の番号)が最初から出力にあったが、答えが文章だけで返る仕組みでは、軸を決めて構造として返させるところが先の仕事になる。呼び出しが一箇所にまとまっていない仕組みでは、目盛りを差す場所を先に作ることになる。目盛りを上げる入れ替えの最中は台ごとに目盛りが揃わず、割合がしばらく揺れる。差分の記録は動いている台の中に溜まるので、台が増えれば散る
  • シミュレータ結果: 五本、〇・〇二五秒。目盛りが0のとき届く答えが組み直す前と変わらないこと、番号が変わった一件が記録に残ること、目盛りを上げるとその利用者にだけ新しいほうが届くこと、同じ利用者が三度呼んでも三度とも同じほうへ行くこと、旧いほうを外した窓口が目盛り100と同じ答えを返すことを確かめた
  • 次の当直への申し送り: 差分が出たときにどこまでを許すかは、まだ決まっていない。持ち帰りになっている。並走のあいだ、届かないほうの答えは急いで受け取る理由がないので、まとめて安く処理する手立てもあるが、今夜の組み方では両方の答えを待つため使えない

使っているものの終わりが外から告げられて、移すしかないと分かっているのに、動いているものを止められないから手を付けられない──モデルの提供終了でも、外部サービスの停止でも、強制的なバージョン更新でも、形は同じです。そういう状態のまま期限が近づいているシステムがあれば、止めずに移す手順を組む相談を承っています。

一斉に切り替えるのではなく、新旧を並べて走らせ、通す割合を少しずつ移していく形です。何をもって「同じ」とみなすかを決めるところから、Meetsource の相談窓口でご相談ください。

comments powered by Disqus
システム開発・AIワークフローのご相談は Meetsource
Hugo で構築されています。
テーマ StackJimmy によって設計されています。