如何在Azure中让Python Flask Web App的指定任务仅在单个实例运行?
解决方案:Azure多实例Flask App中控制单实例任务运行
1. 利用Azure实例标记与环境变量
- 在Azure门户给目标实例添加自定义标记(比如
is_scheduler_instance: true),并通过应用设置注入对应的环境变量IS_SCHEDULER_INSTANCE=true - Flask启动时读取该环境变量,仅在标记实例上启动调度任务
- 代码示例:
import os from flask import Flask from apscheduler.schedulers.background import BackgroundScheduler app = Flask(__name__) def scheduled_job(): # 你的调度任务逻辑 print(f"Task running on instance: {os.getenv('WEBSITE_INSTANCE_ID')}") @app.before_first_request def init_scheduler(): # 判断当前实例是否为调度专用实例 if os.getenv("IS_SCHEDULER_INSTANCE", "false").lower() == "true": scheduler = BackgroundScheduler() scheduler.add_job(scheduled_job, 'interval', minutes=15) scheduler.start() if __name__ == '__main__': app.run()
- 扩展时,只需给需要运行任务的实例保留标记,其他实例不启动调度器
2. 分布式锁实现自动单实例控制
- 用Azure Blob Storage或Redis实现分布式锁,确保同一时间仅一个实例能获取锁并执行任务
- 代码示例(基于Azure Blob Storage):
from azure.storage.blob import BlobServiceClient import os from flask import Flask from apscheduler.schedulers.background import BackgroundScheduler app = Flask(__name__) STORAGE_CONN_STR = os.getenv("AZURE_STORAGE_CONN_STR") LOCK_BLOB = "task-lock" def get_lock(): try: blob_client = BlobServiceClient.from_connection_string(STORAGE_CONN_STR).get_blob_client("locks", LOCK_BLOB) # 创建独占锁,超时设为任务周期的2倍,避免死锁 blob_client.upload_blob(b"locked", overwrite=False, lease_duration=1800) return True except: return False def release_lock(): try: blob_client = BlobServiceClient.from_connection_string(STORAGE_CONN_STR).get_blob_client("locks", LOCK_BLOB) blob_client.delete_blob() except: pass def run_task(): if get_lock(): try: # 任务逻辑 print(f"Task executed on instance: {os.getenv('WEBSITE_INSTANCE_ID')}") finally: release_lock() @app.before_first_request def start_scheduler(): scheduler = BackgroundScheduler() scheduler.add_job(run_task, 'interval', minutes=15) scheduler.start() if __name__ == '__main__': app.run()
- 这种方式无需手动标记实例,动态扩展时自动维持单实例运行
3. 部署槽位隔离方案
- 将调度任务实例放在单独的Azure部署槽位(比如
scheduler-slot),主槽位仅处理Web请求 - 扩展时只增加主槽位的实例数,调度槽位保持单实例
- 优点是任务与Web服务完全隔离,避免互相影响
注意事项
- 若使用Gunicorn等WSGI服务器,需配置worker数量与调度器启动逻辑,避免多worker重复启动任务(可结合进程锁或仅在主worker启动调度器)
- 容器化部署(Azure Container Apps)时,可通过设置调度任务容器的
replicas: 1,结合环境变量控制任务启动
内容的提问来源于stack exchange,提问作者justanotherdeveloper
相关产品推荐
相关产品推荐

