一种埃尔朗风格的纯Scheme Web服务器及其扩展
λ Igropyr λ 一个崩溃自动恢复的Web服务器,代码热替换,故障使用协议,且对话是进程。纯Chez Scheme · Erlang风格的演员 · libuv事件循环 · MIT # macOS: brew install chezscheme libuv · Debian: apt install chezscheme libuv1-dev zlib1g-dev git clone https://github.com/guenchi/Igropyr igropyr export CHEZSCHEMELIBDIRS=. scheme --script igropyr/test/run-otp.sc # curl localhost:8080/ — 尝试终止它: curl localhost:8080/crash 01 · 故障容忍 让它崩溃 每个请求在一个监控的工作池中运行。处理程序不防御 — 它们崩溃,而系统自动恢复。 崩溃自动修复 被崩溃的工作程序立即被替换;任务在一个新的工作程序上重试,最多3次,之后客户端才会看到错误。一个卡住超过30秒的工作程序 — 即便是一个CPU循环 — 会被终止并被替换:抢占式调度意味着没有什么能让服务器卡住。半发送的请求只会停车自己的读取进程,并通过超时清理。其他连接不会注意到。 书写正常流程。监视者负责悲剧。 ( app-get app "/crash" ( lambda (req res) ;; 工作程序死了;监视者在 ;; 新工作程序上重试 -- 池自动填充 ( raise 'handler-crashed ))) ( app-get app "/stuck" ( lambda (req res) ;; 热循环无法冻结系统:抢占 ;; 继续服务,计时器终止此工作程序 ( let loop ((n 0 )) (loop (+ n 1 ))))) 02 · 实时系统 热代码交换 在运行中的服务器上替换处理程序 — 或单个路由。监听程序、开放的连接和工作池保持运行;正在进行的请求在旧代码上完成。 无需重启的部署 路由存在于池后面的可变注册表中。重新注册路径会在下一个请求中原子性地替换它; http-swap! 以同样的方式替换整个处理程序。结合优雅的关闭 ( http-shutdown! 回收正在进行的工作) 和 SO_REUSEPORT多进程监听,零停机操作是默认值,而不是项目。 ( app-get app "/version" ( lambda (req res) ( send-text! res "v1" ))) ;; 点击LIVE服务器上的/upgrade: ( app-get app "/upgrade" ( lambda (req res) ( app-get app "/version" ; 重新注册 = ( lambda (req res) ; 热替换 ( send-text! res "v2 (热替换)" ))) ( send-text! res "已升级" ))) 03 · 远程重试环故障使用协议 当重试耗尽或一个卡住的工作程序被杀死时,Igropyr不会仅仅抛出500 — 它可以告诉客户端到底发生了什么,连接保持打开。 首先被杀死,随后被告知 失败钩子在卡住的工作程序死后回应结构化的故障 — 因此当客户端听到卡住时,没有执行仍在进行中。状态是明确的。 崩溃 — 重试耗尽;用改变的参数重新提交,或进行补偿。 卡住 — 在传输中被杀;重新提交携带状态,或回滚。 保持连接在故障中存活,因此客户端在同一连接上重新提交,并且获得新的重试轮次。缩短卡住时间,曾经看着旋转器30秒的用户现在在同样的时间内通过几个知情的重试,失败在用户界面上变得不可见。 ( app-listen app 8080 `((stuck-ms . 3000 ) ; 快速失败 (check-ms . 1000 ) (on-failure . ,( make-fault-handler )))) ;; 客户端接收,连接保持活跃: ;; {"fault":"崩溃","attempts":4,"retryable":true} ;; {"fault":"卡住","elapsed-ms":3012,...} ;; unset? 普通的500依然存在。零故障。 04 · 使用继续的网络编程 对话是进程 一个多请求的对话 — 一项向导,一个预定,一个转移 — 作为一个绿色进程运行。它的局部绑定是对话状态,包括会话存储永远无法持有的内容:一个开放的数据库事务,跨越多个回合。 控制流是程序文本 "用户在确认步骤" 意味着该过程停在那一行。代码无法表达的步骤顺序不可能发生 — 没有状态机会出错,没有回放需要防御。 消失的保证:因任何原因死亡 — 崩溃、TTL、完成 — 取消注册进程,稍后恢复回应消失。 死进程 = 连接中断 = 数据库本身被回滚:消失证明没有任何提交。结合上述故障代码,客户端始终知道明确的服务器状态 — 一个完整的远程事务环。 ( conversation-start! ( lambda (req suspend!) ( let ((tx (begin-tx!))) ; 活的,通过请求 ( guard (e (#t (rollback! tx) ( raise e))) ( let ((req2 (suspend! confirm-page))) (commit! tx) done)))) req) ( conversation-resume! id req) ; => 回复 | '消失 ;; '消失意味着:已回滚。保证。 基础 它所依赖的 λ 纯Chez Scheme 每一行都是Scheme — R6RS库在.sc中,没有C适配层。 libuv、zlib和MySQL认证的加密通过Chez的FFI直接访问。整个程序编译折叠框架和您的应用为一个优化的二进制文件。 ✉ Erlang风格的演员 绿色进程使用spawn/send/receive、link和monitor、进程注册表、gen-server和PubSub。
本站免费、广告极少。如果觉得有帮助,可以请我们喝杯咖啡 —— 任何金额都对持续运营有实际帮助。
☕请我喝杯咖啡