You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Prometheus Client多进程模式下make_asgi_app返回空字典问题

GitLab Exporter切换FastAPI+Gunicorn后/metrics返回空的问题解决

问题描述

我用prometheus_client开发了一个GitLab自定义Exporter,通过多进程池实现并行数据收集。之前用start_http_server模块时一切正常,但切换到FastAPI+Gunicorn架构后,/metrics接口返回空字典“{}”。目前服务能正常处理请求,数据已完成收集,PROMETHEUS_MULTIPROC_DIR目录也已被正常填充,但指标无法正常返回。

相关代码

当前FastAPI+Gunicorn版本代码

from fastapi import FastAPI
from prometheus_client import make_asgi_app
from gitlab_exporter_func import *
from gitlab_exporter_var import *
import time, os, shutil
import uvicorn

app = FastAPI(debug=False)

@app.get("/metrics")
def get_metrics_app():
    start_time = time.time()

    if os.path.exists(prome_stats):
        shutil.rmtree(prome_stats)
    os.mkdir(prome_stats)

    projects_ids=get_projects()
    get_pipejobs_data(projects_ids)

    end_time = time.time()
    execution_time = end_time - start_time
    print("Execution time:",execution_time)

    return make_asgi_app(registry=registry)

@app.get("/")
async def root():
    return "Go to /metrics for gitlab metrics"      

if __name__ == "__main__":
    uvicorn.run(app, host="127.0.0.1", port=8000)

注册表初始化代码(gitlab_exporter_var.py)

registry = CollectorRegistry()
multiprocess.MultiProcessCollector(registry)

之前正常工作的start_http_server版本参考代码

import prometheus_client
from prometheus_client import start_http_server
from gitlab_exporter_func import *
from gitlab_exporter_var import *
import time
import os
import shutil

prometheus_client.REGISTRY.unregister(prometheus_client.GC_COLLECTOR)
prometheus_client.REGISTRY.unregister(prometheus_client.PLATFORM_COLLECTOR)
prometheus_client.REGISTRY.unregister(prometheus_client.PROCESS_COLLECTOR)

if __name__ == '__main__':
    # Start up the server to expose the metrics.
    start_http_server(8000, registry=registry)
    while(True):

        start_time = time.time()

        if os.path.exists(prome_stats):
            shutil.rmtree(prome_stats)
        os.mkdir(prome_stats)

        projects_ids=get_projects()
        get_pipejobs_data(projects_ids)

        end_time = time.time()
        execution_time = end_time - start_time
        print("Execution time:",execution_time)
        
        time.sleep(max(0, 60-execution_time))        

问题分析

  1. ASGI应用挂载错误:FastAPI路由函数直接返回make_asgi_app的结果是错误的,make_asgi_app生成的是独立ASGI应用,需要通过挂载方式集成,而非作为路由返回值。
  2. 请求触发采集的风险:每次请求/metrics才执行采集逻辑,在Gunicorn多进程模式下会导致进程竞争清理目录,同时重复采集浪费资源。
  3. 注册表初始化时机:多进程环境下,每个Worker进程都会初始化注册表,若目录清理时机不当,会导致指标文件读取不完整。

解决方案

方案1:正确挂载Prometheus ASGI应用+定时采集

调整代码结构,将Prometheus应用挂载到FastAPI中,同时用定时任务执行指标采集,避免请求触发采集:

from fastapi import FastAPI
from prometheus_client import make_asgi_app
from gitlab_exporter_func import *
from gitlab_exporter_var import *
import time, os, shutil
import uvicorn
from apscheduler.schedulers.asyncio import AsyncIOScheduler

app = FastAPI(debug=False)

# 挂载Prometheus ASGI应用到/metrics路径
metrics_app = make_asgi_app(registry=registry)
app.mount("/metrics", metrics_app)

def collect_metrics():
    start_time = time.time()
    # 加锁避免多进程同时清理目录(可选,根据实际情况调整)
    if os.path.exists(prome_stats):
        shutil.rmtree(prome_stats)
    os.mkdir(prome_stats)
    projects_ids=get_projects()
    get_pipejobs_data(projects_ids)
    end_time = time.time()
    execution_time = end_time - start_time
    print("Execution time:",execution_time)

# 启动时执行一次采集,之后每分钟执行一次
@app.on_event("startup")
async def startup_event():
    collect_metrics()
    scheduler = AsyncIOScheduler(timezone="UTC")
    scheduler.add_job(collect_metrics, 'interval', minutes=1)
    scheduler.start()

@app.get("/")
async def root():
    return "Go to /metrics for gitlab metrics"      

if __name__ == "__main__":
    uvicorn.run(app, host="127.0.0.1", port=8000)

关键注意事项

  • 禁止路由返回ASGI应用:必须通过app.mount挂载Prometheus的ASGI应用,确保指标能被正确序列化返回。
  • 定时采集替代请求触发:多进程环境下,请求触发采集易引发资源竞争,定时采集更稳定。
  • 目录清理加锁:若多个Worker进程可能同时执行清理,需添加文件锁避免目录操作冲突。
  • 环境变量一致性:确保PROMETHEUS_MULTIPROC_DIR在所有Gunicorn Worker进程中都能正确读取,目录权限为当前用户可读写。

内容的提问来源于stack exchange,提问作者T.Zampetis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 05:05:16