尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
BentoML 生命周期钩子(Lifecycle Hooks)完全指南:从部署到关机的 Service 管控
模型推理服务人工智能后端大模型MLOpsLLMOps【免费下载链接】BentoMLThe easiest way to serve AI apps and models - Build Model Inference APIs, Job queues, LLM apps, Multi-model pipelines, and more!项目地址https://gitcode.com/gh_mirrors/be/BentoML点击查看免费下载本文围绕 BentoML 官方文档 lifecycle-hooks.rst 展开讲解如何利用bentoml.on_deployment、bentoml.on_startup、bentoml.on_shutdown以及__is_alive__/__is_ready__健康检查钩子在 Service 生命周期的各个阶段插入自定义逻辑。读完本文你将掌握四种钩子的适用场景、编写范式、执行顺序并能结合仓库源码理解其底层触发机制与验证方式为生产级推理服务编写可观测、可优雅启停的初始化与清理流程。一、生命周期钩子是什么在 BentoML 中一个 Service 从「被部署」到「被关闭」会经历多个阶段。生命周期钩子Lifecycle hooks提供了一种机制让你在这些阶段挂载自定义逻辑启动时执行初始化、关机前释放资源、部署前做一次性全局准备以及自定义健康检查判定。它是 BentoML 官方推荐的、将启动/关闭副作用与 API 业务逻辑解耦的标准方式。本文对应的官方文档位于 docs/source/build-with-bentoml/lifecycle-hooks.rst相关概念还涉及 Services 文档、并行与多 Worker 文档 以及 ASGI 应用集成文档。二、理解 Service 服务器生命周期BentoML 的服务器生命周期由若干阶段组成每个阶段都提供了执行特定任务的窗口Deployment hooks部署钩子在任何 worker工作进程 被派生之前运行适合做一次性的全局设置任务。无论最终启动多少个 worker这类操作只应发生一次——这正是 deployment hooks 的关键价值。Spawn workers派生 WorkerBentoML 根据bentoml.service装饰器中配置的workers参数派生相应数量的 worker 进程。Service 初始化与 ASGI 应用启动在每个 worker 启动过程中任何 集成的 ASGI 应用 会开始其生命周期。此时 Service 类的__init__方法被执行可以进行实例级别的初始化如建立数据库连接、加载模型句柄。ASGI 应用拆除teardown最后当服务器关闭包括 ASGI 应用时shutdown 钩子被执行。这一阶段非常适合执行清理任务确保优雅关闭。从源码看执行入口在仓库源码中四类钩子的触发点可以一一对应部署钩子在src/_bentoml_impl/server/serving.py的server_on_deployment函数中被统一调用。该函数还会在调用部署钩子前先解析resolveBento 中引用的所有模型并初始化任务结果存储Sqlite3Store即部署钩子运行在服务器真正拉起任何 worker 之前# src/_bentoml_impl/server/serving.py (节选) def server_on_deployment(svc, result_file...): # Resolve models before server starts. if bento : svc.bento: for model in bento.info.all_models: model.to_model().resolve() ... for name in dir(svc.inner): member getattr(svc.inner, name) if callable(member) and getattr(member, __bentoml_deployment_hook__, False): member()启动钩子在src/_bentoml_impl/server/app.py的create_instance中于self.service()即调用__init__之后逐个执行关闭钩子则对应destroy_instance# src/_bentoml_impl/server/app.py (节选) self._service_instance self.service() # 先执行 __init__ for name in dir(self.service.inner): member getattr(self.service.inner, name) if (not name.startswith(__) and callable(member) and getattr(member, __bentoml_startup_hook__, False)): result getattr(self._service_instance, name)() if inspect.isawaitable(result): await result可以看到钩子方法通过装饰器被标记为__bentoml_startup_hook__/__bentoml_shutdown_hook__/__bentoml_deployment_hook__属性运行时框架再通过反射发现并调用它们装饰器定义见 src/_bentoml_sdk/decorators.py。三、在 Service 中配置钩子本节给出四类钩子的完整配置示例。以下示例均假定你的 Service 以workers4运行用来直观对比全局一次与每 worker 一次的执行差异。3.1 Deployment hooks部署钩子部署钩子类似于静态方法不接收self参数。你可以在一个 Service 中定义多个部署钩子使用bentoml.on_deployment装饰器标记import bentoml bentoml.service(workers4) class HookService: # Deployment hook 不接收 self 参数行为类似于静态方法。 bentoml.on_deployment def prepare(): print(Do some preparation work, running only once.) # 可以定义多个 deployment hooks bentoml.on_deployment def additional_setup(): print(Do more preparation work if needed, also running only once.) def __init__(self) - None: # 启动逻辑和初始化代码 print(This runs on Service startup, once for each worker, so it runs 4 times.) bentoml.api def predict(self, text) - str: # Endpoint 实现逻辑 ...Service 启动后服务端按顺序输出以下日志$ bentoml serve Do some preparation work, running only once. # 第一个 on_deployment hook Do more preparation work if needed, also running only once. # 第二个 on_deployment hook 2024-03-13T03:12:330000 [INFO] [cli] Starting production HTTP BentoServer from service:HookService listening on http://localhost:3000 (Press CTRLC to quit) This runs on Service startup, once for each worker, so it runs 4 times. This runs on Service startup, once for each worker, so it runs 4 times. This runs on Service startup, once for each worker, so it runs 4 times. This runs on Service startup, once for each worker, so it runs 4 times.适用场景迁移数据库 Schema、预热模型缓存目录、清理上一次运行的残留任务文件、生成一次性全局配置等——凡是无论多少个 worker 都只应执行一次的操作都适合放在部署钩子中。从源码可以确认部署钩子使用staticmethod语义见 src/_bentoml_sdk/decorators.py因此不能访问self实例状态如需在钩子与实例间共享数据应借助bentoml.Context详见下文钩子与 Context。3.2 Startup hooks启动钩子启动钩子在 Service 初始化期间执行——位于部署钩子之后、任何 API 端点可用之前。它们每个 worker 运行一次非常适合做 worker 级别的初始化比如建立数据库连接、加载本地资源。使用bentoml.on_startup装饰器标记支持同步与异步两种写法import bentoml bentoml.service(workers4) class HookService: bentoml.on_deployment def prepare(): print(Global preparation, runs once before workers start.) bentoml.on_startup def init_resources(self): # 每个 worker 运行一次 print(Initializing resources for worker.) self.db_connection setup_database() bentoml.on_startup async def init_async_resources(self): # 用于异步初始化任务 print(Async resource initialization for worker.) self.cache await setup_cache() bentoml.api def predict(self, text) - str: # 在 API 端点中使用已初始化的资源 return self.db_connection.query(text)启动该 Service 后你会看到如下输出$ bentoml serve service:HookService Global preparation, runs once before workers start. # on_deployment hook 2024-03-13T03:12:330000 [INFO] [cli] Starting production HTTP BentoServer from service:HookService listening on http://localhost:3000 Initializing resources for worker. # 第一个 worker 的 startup hooks Async resource initialization for worker. Initializing resources for worker. # 第二个 worker 的 startup hooks Async resource initialization for worker. Initializing resources for worker. # 第三个 worker 的 startup hooks Async resource initialization for worker. Initializing resources for worker. # 第四个 worker 的 startup hooks Async resource initialization for worker.要点启动钩子可以定义为async def框架会自动await其结果见 src/_bentoml_impl/server/app.py因此异步资源加载如await setup_cache()可以直接在钩子内完成。由于每个 worker 会独立执行一遍启动钩子初始化逻辑应当具备幂等性避免多个 worker 并发初始化共享资源时产生冲突。启动钩子执行完毕后 API 端点才会对外可用因此它天然承担了就绪前置条件的职责——与下文__is_ready__配合可以构成完整的就绪语义。3.3 Shutdown hooks关闭钩子关闭钩子在 BentoML Service 关闭过程中执行用于执行清理逻辑例如关闭连接、释放资源或其他必要的拆除工作。一个 Service 中可以定义多个关闭钩子。使用bentoml.on_shutdown装饰器标记同样支持同步与异步import bentoml bentoml.service(workers4) class HookService: bentoml.on_deployment def prepare(): print(Do some preparation work, running only once.) def __init__(self) - None: # 启动逻辑和初始化代码 print(This runs on Service startup, once for each worker, so it runs 4 times.) bentoml.api def predict(self, text) - str: # Endpoint 实现逻辑 ... bentoml.on_shutdown def shutdown(self): # 关闭时的逻辑 print(Cleanup actions on Service shutdown.) bentoml.on_shutdown async def async_shutdown(self): print(Async cleanup actions on Service shutdown.)适用场景关闭数据库连接池、刷新内存中的状态到磁盘、通知外部系统如注销服务发现注册、等待进行中的任务落盘等。源码中关闭钩子同样支持同步/异步两种形式见 src/_bentoml_impl/server/app.py框架会按定义顺序逐个执行并await异步钩子。3.4 Health check hooks健康检查钩子健康检查钩子允许你自定义Service 是否健康、是否就绪的判定逻辑。当 Service 依赖外部资源、需要先验证外部依赖可用才认为可以接收流量时这一能力尤其重要。在 Service 类中定义以下两个方法即可实现健康检查方法作用响应的端点返回值__is_alive__检查 Service 是否存活/livezbool表示健康状态__is_ready__检查 Service 是否就绪、可处理请求/readyzbool表示就绪状态两个方法都可以是异步函数。示例一个依赖数据库与缓存的 Serviceimport bentoml bentoml.service(workers4) class HookService: def __init__(self) - None: self.db_connection None self.cache None bentoml.on_startup def init_resources(self): self.db_connection setup_database() self.cache setup_cache() def __is_ready__(self) - bool: # 检查必需资源是否可用 if self.db_connection is None or self.cache is None: return False return self.db_connection.is_connected() and self.cache.is_available()当你调用/readyz端点时如果钩子返回TrueService 就绪返回HTTP 200如果钩子返回FalseService 未就绪返回HTTP 503。源码佐证在 src/_bentoml_impl/server/app.py 中livez与readyz的实现会检测 Service 是否定义了__is_alive__/__is_ready__方法若是异步方法直接await若是同步方法则通过anyio.to_thread.run_sync在线程池中运行避免阻塞事件循环返回False时抛出HTTPException(status_code503)返回True时返回200。readyz还会在runner_probe.enabled开启时检查所有 Runner 的就绪状态任一 Runner 未就绪同样返回 503。与内置端点的关系BentoML Service 默认暴露http://localhost:3000上的三个健康端点——/livez存活探针、/readyz就绪探针、/healthz/livez的别名详见 docs/source/build-with-bentoml/observability/monitoring-and-data-collection.rst。这些端点默认在健康时返回200与空响应体。__is_alive__/__is_ready__的作用是覆盖默认判定未定义时端点总是返回 200Ready 时额外叠加 Runner 探针定义后则以你的自定义逻辑为准。你还可以通过bentoml.service(endpoints{livez: /health, readyz: /ready})自定义端点路径适用于 Service 委托给外部进程、而外部进程使用非标准健康检查路径的场景。注意避免在异步 API 中实现阻塞逻辑否则会阻塞 IO 事件循环导致/readyz等健康检查端点无法正常工作见 docs/source/build-with-bentoml/services.rst。四、钩子与bentoml.Context跨钩子共享状态从源码可以看到在src/bentoml/_internal/service/service.pylegacyService类中启动与关闭钩子会被包装为partial(func, self.context)def on_startup(self, func): self.startup_hooks.append(partial(func, self.context)) return func def on_shutdown(self, func): self.shutdown_hooks.append(partial(func, self.context)) return func def on_deployment(self, func): self.deployment_hooks.append(func) return func这意味着启动钩子和关闭钩子可以接收一个bentoml.Context参数并通过ctx.state在钩子之间传递数据。仓库的端到端测试 tests/e2e/bento_server_http/service.py 展示了这一模式启动钩子写入ctx.state[text_file]关闭钩子读取同一状态并向文件追加关闭标记svc.on_startup def on_startup(ctx: bentoml.Context): ctx.state[data] hello text_file os.path.join(test_dir, fdata-{get_uid()}.txt) with open(text_file, w): pass ctx.state[text_file] text_file svc.on_shutdown def on_shutdown(ctx: bentoml.Context): if text_file not in ctx.state: return with open(ctx.state[text_file], a) as f: f.write(closed\n)对应的测试 tests/e2e/bento_server_http/tests/test_serve.py 以api_workers4启动服务后断言data_files list(tmp_path.glob(data-*.txt)) assert len(data_files) 4, on_startup should be run 4 times for f in data_files: assert f.read_text().strip() closed assert len(list(tmp_path.glob(deployment-*.txt))) 1, ( on_deployment should only be run once )即启动钩子恰好执行 4 次每 worker 一次、部署钩子恰好执行 1 次全局一次且启动/关闭钩子通过 Context 完成的状态传递链路完全可用。这组测试是你验证自己钩子逻辑次数语义的最佳参照。五、钩子执行顺序速查与最佳实践5.1 完整执行顺序以workersN的 HTTP Service 为例从部署到关机的完整顺序为服务器进程启动 └─ on_deployment 钩子全局仅 1 次先于任何 worker 派生 └─ 派生 N 个 worker 进程 └─ 每个 worker 内 ├─ Service 类 __init__每 worker 1 次 ├─ on_startup 钩子同步/异步每 worker 1 次 └─ API 端点对外可用/livez、/readyz、/healthz 生效 ... 服务器关闭SIGINT / SIGTERM └─ 每个 worker 内on_shutdown 钩子同步/异步→ 资源清理 → 进程退出5.2 选择建议钩子类型执行频率是否接收self典型用途bentoml.on_deployment全局 1 次否静态方法语义一次性全局准备Schema 迁移、清残留、预置模型解析bentoml.on_startup每 worker 1 次是建数据库连接、加载资源、异步初始化缓存bentoml.on_shutdown每 worker 1 次是关连接、释放资源、落盘、优雅退出__is_alive__/__is_ready__每次探针请求是自定义存活/就绪判定联动/livez、/readyz5.3 实战建议部署钩子保持幂等虽然只运行一次但建议写成可重入逻辑避免进程被调度平台重复拉起时产生副作用。启动钩子幂等且快速每 worker 都会执行避免对同一外部资源如数据库表做重复的破坏性操作同时钩子完成前端点不可用过长的初始化会拉长就绪时间影响滚动发布与自动伸缩BentoCloud 的零副本伸缩正是通过探测/readyz触发的见 docs/source/scale-with-bentocloud/scaling/autoscaling.rst。异步资源优先用async def钩子框架会正确await避免手动管理线程。关闭钩子要快关闭流程受优雅退出超时约束长时间阻塞的清理逻辑可能导致强制终止。健康检查与启动钩子联动用启动钩子初始化依赖用__is_ready__判定依赖连通性如db_connection.is_connected()形成完整的就绪语义让负载均衡器与调度器准确感知 Service 状态。六、小结BentoML 的生命周期钩子把服务副作用从业务代码中抽离出来提供了四个清晰的插入点全局一次的部署钩子、每 worker 一次的启动/关闭钩子以及由/livez、/readyz驱动的自定义健康检查。本文给出的全部示例均取自官方文档 docs/source/build-with-bentoml/lifecycle-hooks.rst并辅以 decorators.py、serving.py、app.py 等源码实现与 test_serve.py 测试用例加以印证。在生产环境中建议将钩子与监控monitoring-and-data-collection.rst组合使用让每次启动、关闭与健康检查都有迹可循从而构建出可观测、可优雅伸缩的 AI 推理服务。赞分享模型推理服务人工智能后端大模型MLOpsLLMOps【免费下载链接】BentoMLThe easiest way to serve AI apps and models - Build Model Inference APIs, Job queues, LLM apps, Multi-model pipelines, and more!项目地址https://gitcode.com/gh_mirrors/be/BentoML点击查看免费下载相关推荐Livewire 生命周期钩子Lifecycle Hooks完全指南从 mount 到 dehydrate 的组件状态管理Livewire 生命周期钩子Lifecycle Hooks完全指南从 mount 到 dehydrate 的组件状态管理 Livewire 提供了一套完后端前端MNN MnnLlmChat Android 应用发布脚本实战指南从版本号升级到 CDN 与 Google Play 全自动发布MNN MnnLlmChat Android 应用发布脚本实战指南从版本号升级到 CDN 与 Google Play 全自动发布 MnnLlmChat 是 M后端DLSS Swapper不更新游戏如何换DLSS版本DLSS Swapper不更新游戏如何换DLSS版本 你肯定也遇到过这种情况某款游戏内置的DLSS版本很老画面有鬼影、帧率提不上去厂商却迟迟没有计划更新桌面应用上一篇WinPython深度解析Windows平台便携式Python科学计算环境的革命性解决方案下一篇JiYuTrainer深度解析Windows课堂环境下的终极控制权恢复方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED

相关推荐

工业自动化通信协议实战:Modbus、Profinet、EtherCAT、OPC UA详解

工业自动化通信协议实战:Modbus、Profinet、EtherCAT、OPC UA详解

1. 自动化通信协议全景概览干了十几年自动化,从最早拿着RS232串口线蹲在配电柜前面一根一根对线,到后来调EtherCAT伺服轴调到手心冒汗,再到现在坐在办公室远程连OPC UA抓数据,我最大的感受就是:协议这东西,…

📅 2026/9/25 10:21:26
STM32调试报错Internal command error?从硬件链路一步步排查修复

STM32调试报错Internal command error?从硬件链路一步步排查修复

调了几年STM32,Debug模式下突然被一句"Internal command error"打断,估计谁都遇到过。说它是软件问题吧,重装Keil、换驱动都试过,结果依旧;说它是硬件问题吧,板子明明能运行程序,LED闪…

📅 2026/9/25 10:21:26
51单片机霍尔传感器测速系统设计:原理、代码与Proteus仿真全解析

51单片机霍尔传感器测速系统设计:原理、代码与Proteus仿真全解析

做这个51单片机霍尔传感器测速系统,说实话是我这几年带学生做课程设计时被问得最多的项目之一。原因很简单:它麻雀虽小五脏俱全,一个系统里同时包含了传感器接口处理、单片机中断/定时器资源调配、软件滤波、显示驱动、电路仿真和实物搭建&am…

📅 2026/9/25 10:21:26
MORE NEWS

更多资讯

📰

014_角度延迟补偿与高速运行时的转矩跌落

014、角度延迟补偿与高速运行时的转矩跌落 从一个高速主轴项目说起 前年做一个高速主轴驱动项目,额定转速不算特别高,但客户要求最高跑到两万四千转。低速段调试一切正常,电流波形干净,转矩输出也够。问题出在超过一万五千转之后——带载能力明显往下掉,转速再往上拉,电…

📰

从零构建企业级CRM系统:Spring Boot + Vue 3实战指南

1. DeskcommCRM项目概览与核心场景1.1 这个项目要解决的销售管理痛点先说一个我观察到的现象。很多中小团队用Excel管客户,客户的联系方式、跟进记录、报价历史全塞在一张表里,谁改过、什么时候改的,根本查不到。销售离职带走一批客户资料&am…

📰

substrate是什么?跨领域底层支撑概念解析与选型方法论

1. 从“substrate”这个词说起:它到底指什么第一次看到“substrate”这个词,很多人会愣一下。它在不同圈子里含义差别很大:做区块链的人第一反应是 Parity 那套区块链框架;做材料、化学、生物的人想到的是“基底”“底物”“培养基…

📰

Morphe Patches网络层揭秘:3分钟搞懂QUIC禁用、代理路由与证书固定覆盖

Morphe Patches网络层揭秘:3分钟搞懂QUIC禁用、代理路由与证书固定覆盖 【免费下载链接】morphe-patches Morphe Patches 项目地址: https://gitcode.com/gh_mirrors/mo/morphe-patches Morphe Patches 是一套面向移动应用的开源字节码补丁集,它的…

📰

64B/66B编码原理与高速以太网物理层实战解析

1. 什么是64B/66B编码?它不是“加个头”那么简单你可能在查阅IEEE 802.3以太网标准、分析10G/25G/100G PHY层数据流,或者调试高速SerDes链路时,第一次见到“64B/66B”这个缩写。它不像Base64那样用于文本传输,也不像UTF-8那样处理…

📰

基于Python的综合网络安全扫描工具:架构、源码与避坑实践

简介:基于Python3编写的多功能网络安全扫描工具源码包,适用于甲方自测或乙方授权安全评估场景,也适合安全初学者研究常见检测思路。压缩包共41个文件,约6.98MB,核心为31个Python脚本,覆盖敏感文件探测、WAF…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬