Skip to content

Instantly share code, notes, and snippets.

@fukasawah
Last active June 30, 2021 03:56
Show Gist options
  • Save fukasawah/49d77ef6074d7c7eb8e7c241183ad44d to your computer and use it in GitHub Desktop.
Save fukasawah/49d77ef6074d7c7eb8e7c241183ad44d to your computer and use it in GitHub Desktop.
AzureのAppServiceでインスタンス間の排他制御をBlobのLeaseを使って試みるサンプル
#!/bin/sh
set -ue
#
# usage) bash lock-and-run.sh "echo" "hello lock world"
#
### **次の項目は適宜書き換える** ###
STORAGE_ENDPOINT=https://{STORAGE_ACCOUNT_NAME}.blob.core.windows.net
CONTAINER_NAME=test-container
STATUS_FILENAME=my-cron-script.status
N=60
### 設定ここまで
TOKEN_ENDPOINT=${IDENTITY_ENDPOINT:-http://169.254.169.254/metadata/identity/oauth2/token}
if [ "${IDENTITY_HEADER:-}" != "" ]; then
# AppService
HEADER="X-Identity-Header:${IDENTITY_HEADER}"
else
# VM
HEADER="Metadata:true"
fi
# IDMSからアクセストークンを得る
RET=$(curl --fail -H "$HEADER" --noproxy "*" "${TOKEN_ENDPOINT}?api-version=2019-08-01&resource=https%3A%2F%2Fstorage.azure.com%2F")
# PHPでJSONをパースしてアクセストークンを得る
ACCESS_TOKEN=$(echo $RET | /usr/local/bin/php -r "echo json_decode(file_get_contents('php://stdin'))->access_token;" 2>/dev/null)
# もしくはPython
# ACCESS_TOKEN=$(echo $RET | /usr/bin/python3 -c 'import sys,json;print(json.load(sys.stdin)["access_token"])')
STATUS_FILE="$STORAGE_ENDPOINT/$CONTAINER_NAME/$STATUS_FILENAME"
LOCK_FILE="${STATUS_FILE}.lock"
# ロック用のBlobを作る(作成済みの場合はリース中の可能性もあるが、リースを得るためにはまずBlobが存在する必要がある)
curl \
-X PUT \
-d "" \
-H "x-ms-blob-type: BlockBlob" \
-H "x-ms-date: $(TZ=UTC date '+%a, %d %b %Y %H:%M:%S GMT')" \
-H "x-ms-version: 2020-08-04" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
"$LOCK_FILE" >/dev/null
# Blobのリースを得る
GUID=$(cat /proc/sys/kernel/random/uuid)
if ! curl --fail \
-X PUT \
-d "" \
-H "x-ms-date: $(TZ=UTC date '+%a, %d %b %Y %H:%M:%S GMT')" \
-H "x-ms-lease-action: acquire" \
-H "x-ms-lease-duration: 15" \
-H "x-ms-proposed-lease-id: $GUID" \
-H "x-ms-version: 2020-08-04" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
"$LOCK_FILE?comp=lease" >/dev/null ; then
echo "LOCK FAILED(lease)" >&2
exit $?
fi
# ロックしたBlobを読み取る(読み取れたら排他制御成功)
# 読み取れなかったらexitする
if ! curl --fail \
-X GET \
-H "x-ms-lease-id: $GUID" \
-H "x-ms-version: 2020-08-04" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
"$LOCK_FILE" ; then
echo "LOCK FAILED(write)" >&2
exit $?
fi
# ステータスファイルの内容を得る
if ! STATUS=$(curl --fail -X GET -H "x-ms-version: 2020-08-04" -H "Authorization: Bearer $ACCESS_TOKEN" "$STATUS_FILE"); then
echo "READ FAILED(status_file)" >&2
exit $?
fi
# ステータスファイルに記録した日時から N 秒以上経過しているか確認
if [[ "${STATUS:-0}" -g "$(date -d "$N sec ago" +%s)" ]]; then
# 経過していなかったら早すぎたのでスキップ
echo SKIP >&2
exit
fi
# 最後に実行した日時を記録
if ! curl \
--fail \
-X PUT \
-d "$(date +%s)" \
-H "x-ms-blob-type: BlockBlob" \
-H "x-ms-version: 2020-08-04" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
"$STATUS_FILE" >/dev/null ; then
echo "WRITE FAILED(status_file)" >&2
exit $?
fi
### ここまで到達できれば排他制御ができているはず ###
### コマンド実行
exec "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment