PleasanterでGroupIdを取得できずユーザー連携が停止|役職欄の「主席」を調べた事例

よくある誤解

×ジョブが止まったのだから、Pleasanterかプログラムに不具合がある

○プログラムは何も変わっていない。変わったのは、人事側から届いた1つの値

この記事が必要な会社(1つでも当てはまれば対象)

  • 人事情報をもとに、Pleasanterのユーザーやグループを自動更新している
  • 役職や所属を、コード値が来る前提で受け渡している
  • 連携ジョブに、想定外の値が来たときのログを入れていない

今日の一手

人事側から届くCSVの役職欄に、コード以外の文字列が混ざっていないか調べる。

Pleasanterのユーザー・グループ情報を更新する定期ジョブが、人事情報の変更後に正常終了しなくなりました。処理内容を追うと、Pleasanterのグループを設定するために必要なGroupIdを取得できていません。対象ユーザーの元データまで戻ると、本来はシステムで定義されたコードを想定していた役職項目に、「主席」という文字列が入っていました。Pleasanterそのものの障害ではなく、連携処理が前提としていたデータ形式と、実際に渡ってきた値の違いが原因でした。

先に書いておくと、この件はきれいに解決していません。その場は動くようにしましたが、なぜその値が届いたのかは今も分かっておらず、同じことが起きる状態のままです。何をどこまで直して、何を直せていないのかも含めて記録しておきます。

人事情報からPleasanterの所属グループを自動更新していた

今回の環境では、Pleasanterのユーザー情報を管理者がすべて手作業で管理しているわけではありません。人事側から連携用のCSVを受け取り、その内容をもとに定期ジョブがPleasanterのAPIを呼び出して、ユーザーやグループの情報を更新しています。

更新にはPleasanterの API を使っています。この方法なら、人事異動があるたびに管理者がPleasanterを開いて、対象者一人ずつの所属を変更しなくて済みます。普段は非常に便利ですが、自動化された処理には「この項目にはこういう値が入る」という前提があります。

今回の場合、役職に関係する項目には、処理側で認識できるコード値が入ることを想定していました。普段はその前提で問題なく動いていたので、人事情報変更後にジョブが停止するまで、入力値の形式を疑うことはありませんでした。

自動連携では、プログラムが変わっていなくても元データの内容が変われば動かなくなります。今回の調査は、まさにそれでした。

人事システムから連携CSV、連携ジョブ、Pleasanter APIへ至る流れと、CSVの役職欄に混ざった文字列でジョブが停止した箇所を示した図

ジョブ全体ではなく、特定ユーザーを処理したところで問題が起きた

最初に見たのはジョブの実行結果です。すべての利用者で処理できていないなら、Pleasanterへの接続や認証、ジョブ実行環境を疑うことになります。ただ今回は、途中までは処理が進んでいました。

正常に処理されたユーザーと、問題が発生したユーザーの境目を確認して、対象を絞り込みます。そのユーザーについて、所属情報、役職情報、Pleasanter側で設定しようとしているグループを順番に追っていきました。

結果、グループ設定時に必要となるGroupIdを取得できていないことが分かりました。Pleasanterへデータを書き込む処理より前の、「この利用者をどのグループへ所属させるか」という判定部分で止まっていたわけです。

大量データを処理するジョブでは、プログラム全体を最初から読むより、「どのレコードまでは成功し、どのレコードから失敗したのか」を確認するほうが早く原因へ近づけます。

元データまで戻ると、役職項目に「主席」が入っていた

GroupIdを決定する処理がどのデータを参照しているのか確認したところ、連携CSVの役職に関係する項目へ「主席」という文字列が設定されていました。

既存処理は、役職情報として定義済みのコード値が渡される前提です。そのコードを条件にして、Pleasanter上のどのグループへ所属させるかを判定しています。「主席」は既存のコードとして認識できない値なので、対応するグループを判断できず、GroupIdも取得できませんでした。

誤解のないように書いておくと、「主席」という名称そのものが悪いわけではありません。コードを受け取る前提の項目へ、処理側が想定していない形式の値が入ったことが問題です。

コード「10」「20」「30」を想定している処理に「主席」が来たら、どれに対応するのかプログラム側では判断できません。人が見れば意味のある役職名でも、変換ルールがなければシステムでは扱えません。

なぜその値が入ったのかは、今も分かっていない

人事側で手入力されたのか、新設された役職でコードが未定義だったのか、別の理由なのか。特定できていません。原因が分からないということは、次に同じ値が届くかどうかも予測できないということです。

CSVの値を手で直し、差分だけでジョブを再実行した

復旧としてやったことは単純です。連携CSVの中で「主席」となっていた箇所を、処理側が扱えるコード値へ手作業で置き換えました。そのうえで、修正したレコードだけを含む差分CSVを用意し、ジョブを再実行しています。GroupIdが正常に取得され、Pleasanterのユーザー・グループ情報も更新されることを確認しました。

全件を流し直さず差分にしたのは、余計な更新を発生させないためです。前回の実行で正常に処理できたユーザーまで対象に含めると、更新日時が一斉に書き換わりますし、処理時間も伸びます。障害対応では「戻す範囲を最小にする」ほうが、後から影響を追いやすくなります。

もうひとつ、全件を避けた理由があります。Pleasanterのグループ更新APIでは、グループメンバーの更新が洗い替えで行われます。新規に追加するメンバーだけでなく、所属が変わらないメンバーも含めて、すべてを配列に記述するということです。不完全なデータのまま流すと、配列に載らなかった利用者がグループから外れます。障害対応の最中に全件を流し直すのが危ないのは、こういう仕様が背景にあります。

ただし、これは応急処置です。直したのはCSVという途中のデータであって、それを作っている人事側ではありません。次の連携で同じ値が届けば、同じ場所で同じように止まります。

本来なら、正データを管理している上流側で、役職はコードで渡すという取り決めを徹底してもらうべきところです。ですが、人事システムは別部門の管轄で、こちらから仕様を変えられるものではありません。上流は直っていない状態のままです。

障害対応では、復旧そのものと同じくらい「どこを正として、どの項目を修正するのか」の判断が効いてきます。今回はその判断で、正しいほうではなく、動かせるほうを選びました。

ほかの利用者にも同じ値が混ざっていないか確認する

一人の利用者で想定外の値が見つかったとき、その人だけを修正して終わりにすると、次の利用者で同じ問題が出ます。同じ形式の値がほかの利用者にも存在しないか、確認しておきます。

方法としては、役職項目の値と件数を一覧化するのが分かりやすいです。連携CSVをそのまま扱うなら、表計算ソフトで役職列のピボットを作るのが手軽。データベースへ取り込んでから処理しているなら、こういう考え方で値の種類を洗い出せます。

SELECT RoleValue, COUNT(*) AS UserCount
FROM UserSource
GROUP BY RoleValue
ORDER BY RoleValue;

実際のテーブル名や項目名は環境に合わせてください。「どんな値が何件存在するか」を一度一覧にすると、想定外の文字列や未定義コードが見つけやすくなります。件数の多い順に並べれば、正規のコードは上位に固まり、例外的な値は下のほうに残ります。

入力値の検証を入れるべきだと分かっていて、まだ入れていない

今回の処理では、最終的にGroupIdを取得できないところで問題が表面化しました。再発防止を考えるなら、その手前で役職値を検証するほうが分かりやすくなります。

役職コードとして許可している値の一覧を持ち、それ以外を受信した場合は、グループ検索へ進む前に未定義値として記録する。「対象ユーザー」「項目名」「受信値」「未定義であること」がログへ出れば、今回の「主席」のようなケースはすぐ判断できます。今回の調査に費やした時間は、このログが1行あれば数分で済んだはずです。

1件の未定義値でジョブ全体を止めるのか、そのユーザーだけをエラー扱いにしてほかを継続するのかも決めどころです。重要な権限情報を扱うなら停止させるほうが安全ですし、大量ユーザーの同期なら一人だけ隔離して処理を続けるほうが運用しやすい。

ここまで書いておいて何ですが、この検証処理は、まだ実装していません。CSVを直した時点でジョブが通ってしまい、日常の運用に戻ったからです。動くようになると優先度が下がる、というのはよくある話で、今回もそうなりました。

次に同じ場所で止まったとき、私はまた同じ調査を最初からやることになります。それが分かっているうちに手を打つか、もう一度痛い目を見てから手を打つか。この記事は、前者にするための備忘録でもあります。

まとめ

Pleasanterの連携ジョブが止まった原因は、Pleasanterでもプログラムでもなく、人事側から届いたCSVの役職欄に、コードではない文字列が入っていたことでした。切り分けは、「どのレコードまで成功し、どこから失敗したか」を見るのが早道です。

対処としては、CSVの該当箇所をコード値へ手作業で直し、修正分だけの差分CSVでジョブを再実行しました。復旧はしましたが、値が入った理由は不明のままで、上流の人事側も直っていません。同じことが起きる状態は続いています。

自動連携を組むときは、「想定外の値が来る」を前提にしておくのがおすすめです。未定義値をログに残す仕組みが一つあるだけで、次の調査時間はまったく違うものになります。私自身がまだ入れられていない、という実例つきです。

コメント

タイトルとURLをコピーしました