Bazel规则开发:如何处理认证令牌TTL及强制步骤重构建?
解决Bazel中认证令牌缓存过期问题
方法一:强制每次构建重新执行令牌获取步骤
如果你不需要精确的TTL控制,只是想确保每次构建都重新获取令牌,可以通过让目标依赖一个动态变化的伪输入文件,强制Bazel重新执行该步骤。
1. 定义生成动态时间戳的规则
创建一个always_run.bzl文件,实现生成当前时间戳文件的规则:
def _always_run_impl(ctx): out_file = ctx.actions.declare_file(ctx.label.name) ctx.actions.run_shell( outputs = [out_file], command = "date +%s > %s" % (out_file.path), ) return [DefaultInfo(files = depset([out_file]))] always_run = rule( implementation = _always_run_impl, outputs = {"": "%{name}"}, )
2. 在BUILD文件中使用该规则
将时间戳文件作为令牌获取步骤的输入,确保每次构建都触发重新执行:
load("//:always_run.bzl", "always_run") # 生成每次构建都变化的时间戳文件 always_run(name = "build_timestamp") # 获取令牌的genrule,依赖时间戳文件 genrule( name = "fetch_auth_token", srcs = [":build_timestamp"], outs = ["auth_token.txt"], cmd = """ # 替换为你的令牌获取逻辑 curl -s "https://your-auth-endpoint/token" > $@ """, )
替代方案:使用执行要求禁用缓存
对于自定义规则,可在ctx.actions.run中设置execution_requirements直接禁用缓存:
def _fetch_token_impl(ctx): out_token = ctx.actions.declare_file(ctx.label.name + ".txt") ctx.actions.run( outputs = [out_token], executable = ctx.executable._fetch_script, arguments = [out_token.path], execution_requirements = { "no-cache": "true", # 禁用本地缓存 "no-remote-cache": "true", # 禁用远程缓存 }, ) return [DefaultInfo(files = depset([out_token]))] fetch_token = rule( implementation = _fetch_token_impl, executable = "_fetch_script", attrs = { "_fetch_script": attr.label( executable = True, default = Label("//scripts:fetch_token.sh"), cfg = "exec", ), }, )
方法二:基于TTL的令牌复用(近似实现)
Bazel本身没有原生支持TTL缓存失效,但可以通过脚本逻辑结合时间戳输入,实现近似的TTL控制:
1. 编写带过期检查的令牌获取脚本
创建scripts/fetch_token.sh,在脚本中检查现有令牌是否过期,未过期则复用,过期则重新获取:
#!/bin/bash TOKEN_FILE="$1" EXPIRY_FILE="${TOKEN_FILE}.expiry" TOKEN_TTL=3600 # 令牌有效期,单位:秒(示例为1小时) # 检查现有令牌是否有效 if [ -f "$TOKEN_FILE" ] && [ -f "$EXPIRY_FILE" ]; then CURRENT_TIME=$(date +%s) EXPIRY_TIME=$(cat "$EXPIRY_FILE") if [ "$CURRENT_TIME" -lt "$EXPIRY_TIME" ]; then echo "Using existing valid token" exit 0 fi fi # 令牌过期,重新获取 echo "Fetching new token..." NEW_TOKEN=$(curl -s "https://your-auth-endpoint/token") if [ -z "$NEW_TOKEN" ]; then echo "Failed to fetch token" >&2 exit 1 fi # 保存令牌和过期时间 echo "$NEW_TOKEN" > "$TOKEN_FILE" echo $(( $(date +%s) + TOKEN_TTL )) > "$EXPIRY_FILE"
2. 在Bazel规则中使用该脚本
依赖一个按TTL频率更新的时间戳文件(比如每小时更新一次),确保在令牌过期后触发重新执行:
# 生成每小时变化的时间戳文件(匹配令牌TTL) always_run(name = "hourly_timestamp", cmd = "date +%H > %s") genrule( name = "fetch_token_with_ttl", srcs = [":hourly_timestamp"], outs = ["auth_token.txt"], cmd = "$(location //scripts:fetch_token.sh) $@", tools = ["//scripts:fetch_token.sh"], )
针对仓库级令牌的处理(WORKSPACE中)
如果令牌是在仓库初始化阶段获取的,可使用repository_rule结合本地执行逻辑实现TTL检查:
def _token_repo_impl(ctx): import time token_path = ctx.path("auth_token.txt") expiry_path = ctx.path("token_expiry.txt") ttl = 3600 # 1小时有效期 # 检查令牌是否有效 if token_path.exists and expiry_path.exists: with open(expiry_path, "r") as f: expiry = int(f.read().strip()) if time.time() < expiry: ctx.file("BUILD.bazel", 'exports_files(["auth_token.txt"])') return # 重新获取令牌 result = ctx.execute(["curl", "-s", "https://your-auth-endpoint/token"]) if result.return_code != 0: fail("Failed to fetch auth token") token = result.stdout.strip() expiry = int(time.time()) + ttl # 保存令牌和过期时间 ctx.file("auth_token.txt", token) ctx.file("token_expiry.txt", str(expiry)) ctx.file("BUILD.bazel", 'exports_files(["auth_token.txt"])') token_repo = repository_rule( implementation = _token_repo_impl, local = True, # 允许访问本地文件和系统时间 )
在WORKSPACE中调用:
token_repo(name = "my_auth_token")
内容的提问来源于stack exchange,提问作者Ibolit
相关产品推荐
相关产品推荐

