
目次
外部のツールからNotionを更新している。同じデータを、人も画面から編集している。
この状態で、両方が同じ欄を同時に触るとどうなるか。片方が消えます。
しかも、消えたことに気づく手段がありませんでした。実際に測った結果を書きます。
8回試して、8回とも片方が消えました
まず、何が起きるかから。
両方とも「成功しました」と返ってきます
同じ欄を、2か所から同時に更新しました。これを8回繰り返しています。
| 回数 | 返ってきたもの | 残った値 |
|---|---|---|
| 8回とも | 両方「成功しました」 | どちらか一方だけ |
エラーは一度も出ませんでした。両方の処理が、自分は成功したと思って終わります。
記録の上では、何も起きていません
ここが気持ちの悪いところです。処理の記録を見ても、失敗は1件もありません。
| 見るところ | 何が見えるか |
|---|---|
| 外部ツールの実行ログ | 成功。件数も合っている |
| 返ってきた内容 | 自分が送った値が入っている |
| Notionの実際の値 | 別の値になっている |
2つ目に注意してください。更新の返事には、自分が送った値が入って返ってきます。その時点では本当に入っているからです。
そのあとで上書きされます。だから、返事を確認していても防げません。
どちらが勝つかは決まっていません
8回のうち、先に投げたほうが残ったのが3回。あとに投げたほうが残ったのが5回でした。
順番どおりにはなりません。ほぼ同時に投げているので、どちらが先に処理されるかは分からない、ということです。
つまり、毎回同じ結果になるとも限りません。試して「大丈夫だった」としても、次は違うかもしれません。
本文でも同じでした
データベースの欄だけでなく、ページの本文でも同じです。同じ段落を2か所から同時に書き換えると、片方だけが残りました。
こちらも両方「成功しました」と返ってきます。
ただし、値が混ざることはありませんでした。どちらか一方の値が、そのまま入っています。
文字が途中で切れたり、2つの文章がつながったりはしません。壊れるのではなく、片方が丸ごと無かったことになります。
これは救いでもあり、厄介でもあります。値として正常なので、見ただけでは何も起きていないように見えるからです。
止める手段がありません
ふつう、こういうときに使う仕組みがあります。
「変わっていなければ更新する」ができません
自分が読んだときから中身が変わっていたら、更新をやめる。そういう書き方ができれば、上書きは防げます。
これを試しました。読んだときの更新日時を、更新のときに一緒に送ってみます。無視されました。
エラーにはなりません。そのまま更新されます。送った条件は見られていません。
順番に並べる仕組みもありません
もう1つの方法は、更新を1本の列に並べることです。ただ、それはNotion側ではなく、こちら側で作る仕組みになります。
外部ツールが1つだけなら、自分の中で順番に処理すれば済みます。ところが相手は人です。画面から編集する人の操作を、こちらの列に並べることはできません。
ぶつかりやすいのは、こういう場面です
| 場面 | ぶつかりやすさ |
|---|---|
| 同期を毎時間動かしている | 1日に24回の機会がある |
| 朝いちばんに同期している | 出社時刻と重なる |
| 件数が多く、処理に何分もかかる | その間ずっと危ない |
| チームの人数が多い | 誰かが触っている確率が上がる |
3つ目が見落とされがちです。1,000件の書き込みには10分以上かかります。その10分のあいだ、ずっとぶつかる可能性があります。
あとから気づく手段もありません
止められないなら、せめて気づきたい。そう考えます。
更新日時を比べれば分かりそうですが
読んだときの更新日時を覚えておいて、書いたあとにもう一度読む。間に誰かが書いていれば、時刻がずれるはずです。
やってみました。読む、他の人が書く、自分が書く、という順番を作って、時刻を3か所で比べます。
| 時点 | 記録された時刻 |
|---|---|
| 読んだとき | 11時43分00秒 |
| 他の人が書いたあと | 11時43分00秒 |
| 自分が書いたあと | 11時43分00秒 |
全部同じでした。
秒が記録されていません
理由は単純で、更新日時は分までしか残らないからです。秒はいつも00でした。
つまり、同じ1分の中で起きたことは、時刻では区別できません。
そして、上書きが起きるのはまさに同じ1分の中です。検知に使える場面のほうが少ない、ということになります。
二重に詰んでいます
| やりたいこと | できるか |
|---|---|
| 上書きを止める | できない |
| 上書きされたと気づく | できない |
止められず、気づけない。だから、起きない作りにするしかありません。
気づくとしたら、人からの指摘です
実際の現場では、こういう形で発覚します。
| 誰が | 何と言うか |
|---|---|
| 担当者 | 「さっき書いたメモが消えている」 |
| 担当者(しばらく後) | 「前に直したはずなのに、また元に戻っている」 |
| 管理者 | 「同期は成功しているのに、数字が合わない」 |
2つ目がいちばん多いと思います。直すたびに戻るので、人の側が先に気づきます。
そして、この報告を受けても記録には何も残っていません。「同期は正常です」としか答えられない状態になります。
原因が分かるまで時間がかかるのは、このためです。先に知っておくだけで、判断がかなり早くなります。
効いたのは、列を分けることだけです
ここからが本題です。
違う列なら、同時でも両方残ります
今度は、違う列を同時に更新してみました。メモの列と、金額の列です。
| 同時に更新したもの | 結果 |
|---|---|
| 同じ列 | 片方が消える |
| 違う列 | 両方とも残る |
両方そのまま入っていました。消えたものはありません。
つまり、設計で避けられます
上書きが起きるのは、同じ列を両方から書いたときだけです。
ということは、外部ツールが書く列と、人が書く列を分けておけば起きません。
| 列 | 書くのは誰か |
|---|---|
| 外部から入れる情報(受注金額、連携先の状態) | ツールだけ |
| 人が判断して入れる情報(メモ、担当、優先度) | 人だけ |
| 両方が書きたい情報 | 2つの列に分ける |
3つ目が肝です。どうしても両方が書きたい項目は、「ツールが入れた値」と「人が直した値」の2列にします。
2列に分けると、むしろ分かりやすくなります
手間が増えるように見えますが、運用としては良くなる面があります。
| 1列にしていると | 2列に分けると |
|---|---|
| いまの値が誰の判断か分からない | どちらが入れた値か分かる |
| 人が直しても、次の同期で戻る | 人が直した値は残る |
| 直したことが記録に残らない | 元の値と直した値が両方残る |
2つ目が地味に大きいです。1列でやっていると、人が直した値を次の同期が上書きします。直しても直しても戻る、という状態になります。
実際に見るときは、人が直した値があればそちら、なければツールの値という形にします。数式の列を1つ足せば、その1列だけを見れば済みます。
分けられないときは、時間をずらします
列を分けられない場合もあります。そのときは、書く時間をずらしてください。
夜間に動かす、昼休みに動かす。人が触っていない時間なら、そもそもぶつかりません。
完全ではありませんが、起きる確率はかなり下げられます。止める手段がない以上、確率を下げるのが現実的な対処になります。
優先順位をつけると、こうなります
| 順番 | やること | 効き方 |
|---|---|---|
| 1 | ツールが書く列と、人が書く列を分ける | 起きなくなる |
| 2 | 人が触っていない時間に動かす | 確率が下がる |
| 3 | 処理時間を短くする(変わった行だけ書く) | 危ない時間が縮む |
| 4 | 更新の直前にもう一度読む | ほぼ気休め |
4番目に期待しないでください。読んでから送るまでの間に書かれたら、同じことが起きます。隙間が狭くなるだけです。
1番だけが、確実に効きます。ほかは全部、確率の話です。
図にすると、こういう状況です
送った列だけが変わります
ここまでの前提になっている仕組みも書いておきます。
全部を送り直す必要はありません
金額の列だけを更新してみました。ほかの列はそのままでした。
| 列 | 更新後 |
|---|---|
| 金額(送った) | 新しい値 |
| メモ(送っていない) | 元のまま |
| タグ(送っていない) | 元のまま |
送らなかった列は、触られません。全件を読んでから全件を書き戻す、という作りにする必要はありません。
だから、列を分ける作戦が効きます
この仕組みがあるから、前の章の話が成り立ちます。ツールが自分の列だけを送っていれば、人の列には一切触れません。
逆に言えば、「念のため全部の列を送る」という作りにしていると、列を分けた意味がなくなります。必要な列だけを送ってください。
読んだ内容をそのまま送り返す作りも同じです。変えていない列まで送ることになります。
| 送り方 | 人の列を壊すか |
|---|---|
| 変えたい列だけを送る | 壊さない |
| 読んだ内容を丸ごと送り返す | 壊す |
| 念のため全部の列を送る | 壊す |
下2つは、値が同じなら害がないように見えます。ただ、読んでから送るまでに人が直していたら、その直しを消します。
とくに、件数が多くて処理に時間がかかるほど危なくなります。最初の行を読んでから最後の行を書き終えるまでが、まるごと危ない時間になるからです。
読むのと書くのを一度に済ませたくなりますが、変えたい列だけを送る形にしておくほうが安全です。
知らずに消してしまう、もう1つの形
最後に、似た事故をもう1つ。
タグは、送った内容で全部置き換わります
複数選べるタグの列に、タグを1つ足したい。そう思って、足したいタグだけを送りました。
| タグの中身 | |
|---|---|
| 更新前 | A |
| 送ったもの | B |
| 更新後 | B だけ(A が消えた) |
足すのではなく、置き換わります。
足したいときは、読んでから送ります
いまのタグを読んで、そこに足した配列を作って、まとめて送る。この順番が必要です。
ただし、読んでから送るまでの間に人がタグを変えていると、そこでも上書きが起きます。この記事の最初の話と同じです。
選択肢そのものを消したときの話も書きました。値の側と、選択肢の側。どちらも「送ったもので全部置き換わる」という同じ性質です。
よくある質問(FAQ)
上書きが起きたかどうかを、あとから調べる方法はありませんか。
更新日時は分までしか残らないので、同じ分の中で起きたことは区別できませんでした。画面の履歴で追える可能性はありますが、そちらは今回検証していません。
外部ツールを1つに絞れば起きませんか。
人が画面から編集するなら、同じことが起きます。相手はツールとは限りません。
更新の直前にもう一度読めば、防げませんか。
読んでから送るまでの間に書かれると、同じです。確率は下がりますが、なくなりません。列を分けるほうが確実です。
どうしても同じ列を両方から書きたいです。
2つの列に分けて、画面で見るときに両方を並べるのが現実的です。あるいは、人が触っていない時間にツールを動かしてください。
タグを1つだけ消したいときも、同じですか。
同じです。いまの値を読んで、消したいものを除いた配列を作って送ることになります。
同時に更新すると、データが壊れたりしませんか。
今回の範囲では、壊れた値は出ませんでした。どちらか一方の値が、そのまま入っていました。混ざることはありません。
ツールが書く列と、人が書く列を分けてください
同じ列を同時に更新すると、両方「成功しました」と返ってきて片方が消えます。止める手段も気づく手段もありません。違う列なら両方残るので、分けておくのが唯一の対策です。