0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

OAuth認可による外部サービスとの通信で排他制御を導入した

0
Posted at

背景

業務の振り返りとしてここにまとめます。
外部サービスとOAuth認可で連携する機能があり、その際のトークンに関わる処理の見直しをしました。

前提
メインサーバー、イベントをリッスンし実行するワーカーサーバー、バッチ用のサーバーから同一の外部サービスにリクエストを送るため、プロセス内に限らず、マルチプロセスでの並列リクエストが起こり得る設計になっています。

当時の処理

リクエストの度に以下を行っていました。

  • リフレッシュトークンでアクセストークンを更新する
  • そのアクセストークンで外部サービスにリクエストを投げる
  • 更新されたアクセストークンはDBに保持しない

リフレッシュトークンは同じものを使い続けています。

外部サービスの仕様変更による連携の障害

外部サービスの仕様が以下のように変わりました。

  • アクセストークン更新時にリフレッシュトークンも更新する

これにより、アプリは更新されたリフレッシュトークンをDBに保持することはしないため、2回目のリクエストで失敗するという障害が起こりました。

対応方針 「期限切れになるまで access_token を使い回す」

理由

  • 毎回アクセストークンを更新する運用の場合、直列で各リクエストを行うようにするとロック待機時間が課題となる
    • refresh すると既存の access_token を失効させることも分かったため

前提: 毎回refreshする運用では、並列リクエストは成立しない(競合して失敗する)

しかしロックにより直列化すると、ロック待機時間が課題となる

採用案: access_token を使い回す

access_tokenが期限切れの際のrefresh周りで排他制御をする

access_tokenが期限切れの場合はrefreshをします。
その際に並列リクエストが走る場合を考慮します。

先にリクエストを実行する予定だったもの(リクエストA)のaccess_tokenが、後続リクエストによりrefreshされると、リクエストAは失敗します。

そのため、以下のように排他制御が必要になります。

refresh周りの排他制御の技術選定

物理ロック(行ロック)を取得せず、論理ロックを取得することにした理由

  • 行ロックだと、その間 トークンをカラムに持つテーブルの同一行を触る無関係なトランザクションがブロックされるため
  • 論理ロックは同じキーを取りに来たトークン更新リクエストに対してブロック(直列化)することができる

pg_advisory_xact_lock はDBサーバー側のロックなので、バッチ用のサーバーも、mainのサーバーも同じキーを使うことでマルチプロセス間での排他制御をすることが可能です。
ロックはトランザクション終了時に自動解放されます。

参考

DB

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?