@rivetkit/engine 1.0.0 → 2.2.1-pr.4600.b74ff3b

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1038) hide show
  1. package/CLAUDE.md +38 -0
  2. package/artifacts/config-schema.json +1140 -0
  3. package/artifacts/errors/actor.kv_storage_quota_exceeded.json +5 -0
  4. package/artifacts/errors/actor.no_runner_config_configured.json +5 -0
  5. package/artifacts/errors/guard.actor_runner_failed.json +5 -0
  6. package/artifacts/errors/guard.invalid_request.json +5 -0
  7. package/artifacts/errors/guard.invalid_request_body.json +5 -0
  8. package/artifacts/errors/guard.invalid_response_body.json +5 -0
  9. package/artifacts/errors/guard.missing_query_parameter.json +5 -0
  10. package/artifacts/errors/guard.query_ambiguous_runner_configs.json +5 -0
  11. package/artifacts/errors/guard.query_duplicate_param.json +5 -0
  12. package/artifacts/errors/guard.query_empty_actor_name.json +5 -0
  13. package/artifacts/errors/guard.query_get_disallowed_params.json +5 -0
  14. package/artifacts/errors/guard.query_invalid_base64_input.json +5 -0
  15. package/artifacts/errors/guard.query_invalid_cbor_input.json +5 -0
  16. package/artifacts/errors/guard.query_invalid_params.json +5 -0
  17. package/artifacts/errors/guard.query_invalid_percent_encoding.json +5 -0
  18. package/artifacts/errors/guard.query_missing_runner_name.json +5 -0
  19. package/artifacts/errors/guard.query_no_runner_configs.json +5 -0
  20. package/artifacts/errors/guard.query_param_missing_equals.json +5 -0
  21. package/artifacts/errors/guard.query_path_token_syntax.json +5 -0
  22. package/artifacts/errors/guard.query_unknown_param.json +5 -0
  23. package/artifacts/errors/guard.request_body_too_large.json +5 -0
  24. package/artifacts/errors/guard.response_body_too_large.json +5 -0
  25. package/artifacts/errors/serverless_runner_pool.failed_to_fetch_metadata.json +5 -0
  26. package/artifacts/errors/serverless_runner_pool.not_found.json +5 -0
  27. package/artifacts/errors/{api.rate_limited.json → test.api_rate_limited.json} +2 -2
  28. package/artifacts/errors/{namespace.invalid_name.json → test.namespace_invalid_name.json} +2 -2
  29. package/artifacts/errors/ws.going_away.json +5 -0
  30. package/artifacts/openapi.json +458 -6
  31. package/docker/builder-base/linux-gnu.Dockerfile +21 -0
  32. package/docker/builder-base/linux-musl.Dockerfile +53 -0
  33. package/docker/builder-base/osxcross.Dockerfile +42 -0
  34. package/docker/builder-base/windows-mingw.Dockerfile +41 -0
  35. package/docker/builder-base/windows-msvc.Dockerfile +25 -0
  36. package/docker/dev/docker-compose.yml +43 -18
  37. package/docker/dev/grafana/dashboards/api.json +1077 -1239
  38. package/docker/dev/grafana/dashboards/cache.json +911 -1074
  39. package/docker/dev/grafana/dashboards/epoxy.json +1606 -0
  40. package/docker/dev/grafana/dashboards/futures.json +242 -229
  41. package/docker/dev/grafana/dashboards/gasoline.json +2663 -2476
  42. package/docker/dev/grafana/dashboards/guard.json +1433 -1273
  43. package/docker/dev/grafana/dashboards/operation.json +871 -0
  44. package/docker/dev/grafana/dashboards/pegboard.json +1274 -0
  45. package/docker/dev/grafana/dashboards/tokio.json +930 -1004
  46. package/docker/dev/grafana/dashboards/traces.json +35 -13
  47. package/docker/dev/grafana/provisioning/datasources/datasources.yaml +8 -0
  48. package/docker/{dev-multinode/otel-collector-server → dev/otel-collector}/config.yaml +18 -13
  49. package/docker/dev/prometheus/prometheus.yml +4 -0
  50. package/docker/dev/rivet-engine/config.jsonc +9 -16
  51. package/docker/dev-host/docker-compose.yml +38 -16
  52. package/docker/dev-host/grafana/dashboards/api.json +1077 -1239
  53. package/docker/dev-host/grafana/dashboards/cache.json +911 -1074
  54. package/docker/dev-host/grafana/dashboards/epoxy.json +1606 -0
  55. package/docker/dev-host/grafana/dashboards/futures.json +242 -229
  56. package/docker/dev-host/grafana/dashboards/gasoline.json +2663 -2476
  57. package/docker/dev-host/grafana/dashboards/guard.json +1433 -1273
  58. package/docker/dev-host/grafana/dashboards/operation.json +871 -0
  59. package/docker/dev-host/grafana/dashboards/pegboard.json +1274 -0
  60. package/docker/dev-host/grafana/dashboards/tokio.json +930 -1004
  61. package/docker/dev-host/grafana/dashboards/traces.json +35 -13
  62. package/docker/dev-host/grafana/provisioning/datasources/datasources.yaml +8 -0
  63. package/docker/dev-host/{otel-collector-server → otel-collector}/config.yaml +18 -13
  64. package/docker/dev-host/prometheus/prometheus.yml +4 -0
  65. package/docker/dev-host/rivet-engine/config.jsonc +9 -16
  66. package/docker/dev-multidc/core/grafana/dashboards/api.json +1077 -1239
  67. package/docker/dev-multidc/core/grafana/dashboards/cache.json +911 -1074
  68. package/docker/dev-multidc/core/grafana/dashboards/epoxy.json +1606 -0
  69. package/docker/dev-multidc/core/grafana/dashboards/futures.json +242 -229
  70. package/docker/dev-multidc/core/grafana/dashboards/gasoline.json +2663 -2476
  71. package/docker/dev-multidc/core/grafana/dashboards/guard.json +1433 -1273
  72. package/docker/dev-multidc/core/grafana/dashboards/operation.json +871 -0
  73. package/docker/dev-multidc/core/grafana/dashboards/pegboard.json +1274 -0
  74. package/docker/dev-multidc/core/grafana/dashboards/tokio.json +930 -1004
  75. package/docker/dev-multidc/core/grafana/dashboards/traces.json +35 -13
  76. package/docker/dev-multidc/core/grafana/provisioning/datasources/datasources.yaml +8 -0
  77. package/docker/dev-multidc/core/prometheus/prometheus.yml +4 -0
  78. package/docker/dev-multidc/datacenters/dc-a/{otel-collector-server → otel-collector}/config.yaml +18 -13
  79. package/docker/dev-multidc/datacenters/dc-a/rivet-engine/config.jsonc +23 -22
  80. package/docker/{dev-multidc-multinode/datacenters/dc-b/otel-collector-server → dev-multidc/datacenters/dc-b/otel-collector}/config.yaml +18 -13
  81. package/docker/dev-multidc/datacenters/dc-b/rivet-engine/config.jsonc +23 -22
  82. package/docker/dev-multidc/datacenters/dc-c/{otel-collector-server → otel-collector}/config.yaml +18 -13
  83. package/docker/dev-multidc/datacenters/dc-c/rivet-engine/config.jsonc +23 -22
  84. package/docker/dev-multidc/docker-compose.yml +71 -64
  85. package/docker/dev-multidc-multinode/core/grafana/dashboards/api.json +1077 -1239
  86. package/docker/dev-multidc-multinode/core/grafana/dashboards/cache.json +911 -1074
  87. package/docker/dev-multidc-multinode/core/grafana/dashboards/epoxy.json +1606 -0
  88. package/docker/dev-multidc-multinode/core/grafana/dashboards/futures.json +242 -229
  89. package/docker/dev-multidc-multinode/core/grafana/dashboards/gasoline.json +2663 -2476
  90. package/docker/dev-multidc-multinode/core/grafana/dashboards/guard.json +1433 -1273
  91. package/docker/dev-multidc-multinode/core/grafana/dashboards/operation.json +871 -0
  92. package/docker/dev-multidc-multinode/core/grafana/dashboards/pegboard.json +1274 -0
  93. package/docker/dev-multidc-multinode/core/grafana/dashboards/tokio.json +930 -1004
  94. package/docker/dev-multidc-multinode/core/grafana/dashboards/traces.json +35 -13
  95. package/docker/dev-multidc-multinode/core/grafana/provisioning/datasources/datasources.yaml +8 -0
  96. package/docker/dev-multidc-multinode/core/prometheus/prometheus.yml +4 -0
  97. package/docker/dev-multidc-multinode/datacenters/dc-a/{otel-collector-server → otel-collector}/config.yaml +28 -13
  98. package/docker/dev-multidc-multinode/datacenters/dc-a/rivet-engine/0/config.jsonc +23 -22
  99. package/docker/dev-multidc-multinode/datacenters/dc-a/rivet-engine/1/config.jsonc +23 -22
  100. package/docker/dev-multidc-multinode/datacenters/dc-a/rivet-engine/2/config.jsonc +23 -22
  101. package/docker/{dev-multidc/datacenters/dc-b/otel-collector-server → dev-multidc-multinode/datacenters/dc-b/otel-collector}/config.yaml +28 -13
  102. package/docker/dev-multidc-multinode/datacenters/dc-b/rivet-engine/0/config.jsonc +23 -22
  103. package/docker/dev-multidc-multinode/datacenters/dc-b/rivet-engine/1/config.jsonc +23 -22
  104. package/docker/dev-multidc-multinode/datacenters/dc-b/rivet-engine/2/config.jsonc +23 -22
  105. package/docker/dev-multidc-multinode/datacenters/dc-c/{otel-collector-server → otel-collector}/config.yaml +28 -13
  106. package/docker/dev-multidc-multinode/datacenters/dc-c/rivet-engine/0/config.jsonc +23 -22
  107. package/docker/dev-multidc-multinode/datacenters/dc-c/rivet-engine/1/config.jsonc +23 -22
  108. package/docker/dev-multidc-multinode/datacenters/dc-c/rivet-engine/2/config.jsonc +23 -22
  109. package/docker/dev-multidc-multinode/docker-compose.yml +113 -88
  110. package/docker/dev-multinode/docker-compose.yml +57 -26
  111. package/docker/dev-multinode/grafana/dashboards/api.json +1077 -1239
  112. package/docker/dev-multinode/grafana/dashboards/cache.json +911 -1074
  113. package/docker/dev-multinode/grafana/dashboards/epoxy.json +1606 -0
  114. package/docker/dev-multinode/grafana/dashboards/futures.json +242 -229
  115. package/docker/dev-multinode/grafana/dashboards/gasoline.json +2663 -2476
  116. package/docker/dev-multinode/grafana/dashboards/guard.json +1433 -1273
  117. package/docker/dev-multinode/grafana/dashboards/operation.json +871 -0
  118. package/docker/dev-multinode/grafana/dashboards/pegboard.json +1274 -0
  119. package/docker/dev-multinode/grafana/dashboards/tokio.json +930 -1004
  120. package/docker/dev-multinode/grafana/dashboards/traces.json +35 -13
  121. package/docker/dev-multinode/grafana/provisioning/datasources/datasources.yaml +8 -0
  122. package/docker/{dev/otel-collector-server → dev-multinode/otel-collector}/config.yaml +28 -13
  123. package/docker/dev-multinode/prometheus/prometheus.yml +4 -0
  124. package/docker/dev-multinode/rivet-engine/0/config.jsonc +9 -16
  125. package/docker/dev-multinode/rivet-engine/1/config.jsonc +9 -16
  126. package/docker/dev-multinode/rivet-engine/2/config.jsonc +9 -16
  127. package/docker/engine/linux-aarch64.Dockerfile +9 -49
  128. package/docker/engine/linux-x86_64.Dockerfile +7 -57
  129. package/docker/engine/macos-aarch64.Dockerfile +8 -54
  130. package/docker/engine/macos-x86_64.Dockerfile +9 -55
  131. package/docker/engine/windows.Dockerfile +5 -53
  132. package/docker/template/grafana-dashboards/api.json +1077 -1239
  133. package/docker/template/grafana-dashboards/cache.json +911 -1074
  134. package/docker/template/grafana-dashboards/epoxy.json +1606 -0
  135. package/docker/template/grafana-dashboards/futures.json +242 -229
  136. package/docker/template/grafana-dashboards/gasoline.json +2663 -2476
  137. package/docker/template/grafana-dashboards/guard.json +1433 -1273
  138. package/docker/template/grafana-dashboards/operation.json +871 -0
  139. package/docker/template/grafana-dashboards/pegboard.json +1274 -0
  140. package/docker/template/grafana-dashboards/tokio.json +930 -1004
  141. package/docker/template/grafana-dashboards/traces.json +35 -13
  142. package/docker/template/node_modules/.bin/js-yaml +4 -4
  143. package/docker/template/node_modules/.bin/tsc +4 -4
  144. package/docker/template/node_modules/.bin/tsserver +4 -4
  145. package/docker/template/node_modules/.bin/tsx +4 -4
  146. package/docker/template/src/docker-compose.ts +42 -29
  147. package/docker/template/src/main.ts +4 -4
  148. package/docker/template/src/services/core/grafana.ts +14 -1
  149. package/docker/template/src/services/core/prometheus.ts +20 -0
  150. package/docker/template/src/services/edge/{otel-collector-server.ts → otel-collector.ts} +55 -24
  151. package/docker/template/src/services/edge/rivet-engine.ts +4 -16
  152. package/docker/template/src/services/edge/runner.ts +2 -3
  153. package/docker/universal/Dockerfile +5 -3
  154. package/package.json +2 -5
  155. package/packages/api-builder/src/global_context.rs +1 -1
  156. package/packages/api-builder/src/metrics.rs +28 -24
  157. package/packages/api-builder/src/middleware.rs +30 -48
  158. package/packages/api-builder/src/router.rs +13 -1
  159. package/packages/api-peer/Cargo.toml +7 -9
  160. package/packages/api-peer/src/actors/delete.rs +56 -57
  161. package/packages/api-peer/src/actors/get_or_create.rs +139 -0
  162. package/packages/api-peer/src/actors/kv_get.rs +40 -28
  163. package/packages/api-peer/src/actors/list.rs +31 -14
  164. package/packages/api-peer/src/actors/list_names.rs +6 -6
  165. package/packages/api-peer/src/actors/mod.rs +3 -0
  166. package/packages/api-peer/src/actors/reschedule.rs +55 -0
  167. package/packages/api-peer/src/actors/sleep.rs +55 -0
  168. package/packages/api-peer/src/envoys.rs +57 -0
  169. package/packages/api-peer/src/internal.rs +441 -24
  170. package/packages/api-peer/src/lib.rs +2 -1
  171. package/packages/api-peer/src/namespaces.rs +24 -9
  172. package/packages/api-peer/src/router.rs +31 -7
  173. package/packages/api-peer/src/runner_configs.rs +66 -19
  174. package/packages/api-peer/src/runners.rs +30 -32
  175. package/packages/api-public/Cargo.toml +2 -0
  176. package/packages/api-public/src/actors/create.rs +8 -17
  177. package/packages/api-public/src/actors/delete.rs +11 -35
  178. package/packages/api-public/src/actors/get_or_create.rs +23 -95
  179. package/packages/api-public/src/actors/kv_get.rs +12 -29
  180. package/packages/api-public/src/actors/list.rs +56 -78
  181. package/packages/api-public/src/actors/list_names.rs +15 -14
  182. package/packages/api-public/src/actors/mod.rs +2 -0
  183. package/packages/api-public/src/actors/reschedule.rs +65 -0
  184. package/packages/api-public/src/actors/sleep.rs +64 -0
  185. package/packages/api-public/src/actors/utils.rs +12 -60
  186. package/packages/api-public/src/ctx.rs +14 -6
  187. package/packages/api-public/src/datacenters.rs +5 -5
  188. package/packages/api-public/src/envoys.rs +57 -0
  189. package/packages/api-public/src/errors.rs +0 -7
  190. package/packages/api-public/src/health.rs +51 -44
  191. package/packages/api-public/src/lib.rs +2 -1
  192. package/packages/api-public/src/metadata.rs +44 -14
  193. package/packages/api-public/src/namespaces.rs +11 -11
  194. package/packages/api-public/src/router.rs +22 -5
  195. package/packages/api-public/src/runner_configs/delete.rs +13 -10
  196. package/packages/api-public/src/runner_configs/list.rs +5 -2
  197. package/packages/api-public/src/runner_configs/refresh_metadata.rs +1 -1
  198. package/packages/api-public/src/runner_configs/serverless_health_check.rs +2 -2
  199. package/packages/api-public/src/runner_configs/upsert.rs +12 -9
  200. package/packages/api-public/src/runner_configs/utils.rs +35 -175
  201. package/packages/api-public/src/runners.rs +17 -45
  202. package/packages/{dump-openapi → api-public-openapi-gen}/Cargo.toml +1 -1
  203. package/packages/api-types/src/actors/create.rs +1 -0
  204. package/packages/api-types/src/actors/delete.rs +20 -0
  205. package/packages/api-types/src/actors/get_or_create.rs +30 -0
  206. package/packages/api-types/src/actors/kv_get.rs +25 -0
  207. package/packages/api-types/src/actors/list.rs +8 -1
  208. package/packages/api-types/src/actors/mod.rs +5 -0
  209. package/packages/api-types/src/actors/reschedule.rs +26 -0
  210. package/packages/api-types/src/actors/sleep.rs +26 -0
  211. package/packages/api-types/src/datacenters/list.rs +2 -2
  212. package/packages/api-types/src/envoys/list.rs +24 -0
  213. package/packages/api-types/src/envoys/mod.rs +1 -0
  214. package/packages/api-types/src/lib.rs +1 -0
  215. package/packages/api-types/src/namespaces/list.rs +4 -0
  216. package/packages/api-types/src/namespaces/runner_configs.rs +23 -2
  217. package/packages/api-types/src/runner_configs/list.rs +6 -1
  218. package/packages/api-types/src/runner_configs/mod.rs +12 -0
  219. package/packages/api-types/src/runners/list.rs +4 -0
  220. package/packages/api-types/src/runners/list_names.rs +21 -0
  221. package/packages/api-types/src/runners/mod.rs +1 -0
  222. package/packages/api-util/src/lib.rs +44 -21
  223. package/packages/bootstrap/Cargo.toml +7 -4
  224. package/packages/bootstrap/src/backfill.rs +53 -0
  225. package/packages/bootstrap/src/lib.rs +43 -7
  226. package/packages/cache/Cargo.toml +3 -1
  227. package/packages/cache/src/driver.rs +43 -151
  228. package/packages/cache/src/getter_ctx.rs +48 -70
  229. package/packages/cache/src/inner.rs +28 -18
  230. package/packages/cache/src/key.rs +17 -3
  231. package/packages/cache/src/lib.rs +0 -2
  232. package/packages/cache/src/metrics.rs +43 -31
  233. package/packages/cache/src/req_config.rs +219 -156
  234. package/packages/cache/tests/fetch.rs +91 -0
  235. package/packages/cache/tests/in_flight.rs +361 -0
  236. package/packages/cache/tests/ttl.rs +314 -0
  237. package/packages/cache-purge/src/lib.rs +1 -1
  238. package/packages/config/Cargo.toml +1 -0
  239. package/packages/config/src/config/cache.rs +10 -3
  240. package/packages/config/src/config/clickhouse.rs +0 -30
  241. package/packages/config/src/config/{db.rs → db/mod.rs} +3 -18
  242. package/packages/config/src/config/db/postgres.rs +59 -0
  243. package/packages/config/src/config/guard.rs +19 -0
  244. package/packages/config/src/config/metrics.rs +22 -0
  245. package/packages/config/src/config/mod.rs +44 -10
  246. package/packages/config/src/config/pegboard.rs +242 -16
  247. package/packages/config/src/config/pubsub.rs +11 -0
  248. package/packages/config/src/config/runtime.rs +58 -0
  249. package/packages/config/src/config/telemetry.rs +1 -0
  250. package/packages/config/src/config/topology.rs +78 -19
  251. package/packages/config/src/defaults.rs +3 -0
  252. package/packages/config/src/lib.rs +10 -1
  253. package/packages/config-schema-gen/Cargo.toml +11 -0
  254. package/packages/config-schema-gen/build.rs +26 -0
  255. package/packages/config-schema-gen/src/lib.rs +2 -0
  256. package/packages/engine/Cargo.toml +11 -2
  257. package/packages/engine/src/commands/db/mod.rs +0 -10
  258. package/packages/engine/src/commands/epoxy.rs +395 -0
  259. package/packages/engine/src/commands/mod.rs +1 -1
  260. package/packages/engine/src/commands/start.rs +43 -63
  261. package/packages/engine/src/commands/udb/cli.rs +148 -4
  262. package/packages/engine/src/commands/wf/mod.rs +83 -12
  263. package/packages/engine/src/commands/wf/signal.rs +38 -0
  264. package/packages/engine/src/lib.rs +6 -3
  265. package/packages/engine/src/main.rs +1 -1
  266. package/packages/engine/src/run_config.rs +6 -7
  267. package/packages/engine/src/util/db.rs +1 -25
  268. package/packages/engine/src/util/wf/mod.rs +39 -5
  269. package/packages/engine/tests/common/actors.rs +50 -332
  270. package/packages/engine/tests/common/api/mod.rs +7 -0
  271. package/packages/engine/tests/common/api/peer.rs +364 -0
  272. package/packages/engine/tests/common/api/public.rs +473 -0
  273. package/packages/engine/tests/common/ctx.rs +15 -3
  274. package/packages/engine/tests/common/mod.rs +8 -5
  275. package/packages/engine/tests/common/test_envoy.rs +87 -0
  276. package/packages/engine/tests/common/test_helpers.rs +218 -130
  277. package/packages/engine/tests/common/test_runner.rs +273 -0
  278. package/packages/engine/tests/envoy/actors_lifecycle.rs +1277 -0
  279. package/packages/engine/tests/envoy/mod.rs +1 -0
  280. package/packages/engine/tests/mod.rs +3 -0
  281. package/packages/engine/tests/runner/actors_alarm.rs +1453 -0
  282. package/packages/engine/tests/runner/actors_kv_crud.rs +996 -0
  283. package/packages/engine/tests/runner/actors_kv_delete_range.rs +126 -0
  284. package/packages/engine/tests/runner/actors_kv_drop.rs +255 -0
  285. package/packages/engine/tests/runner/actors_kv_list.rs +1061 -0
  286. package/packages/engine/tests/runner/actors_kv_misc.rs +882 -0
  287. package/packages/engine/tests/runner/actors_lifecycle.rs +1284 -0
  288. package/packages/engine/tests/runner/actors_scheduling_errors.rs +1005 -0
  289. package/packages/engine/tests/runner/api_actors_create.rs +422 -0
  290. package/packages/engine/tests/runner/api_actors_delete.rs +487 -0
  291. package/packages/engine/tests/runner/api_actors_get_or_create.rs +634 -0
  292. package/packages/engine/tests/runner/api_actors_list.rs +1771 -0
  293. package/packages/engine/tests/runner/api_actors_list_names.rs +691 -0
  294. package/packages/engine/tests/runner/api_namespaces_create.rs +428 -0
  295. package/packages/engine/tests/runner/api_namespaces_list.rs +760 -0
  296. package/packages/engine/tests/runner/api_runner_configs_list.rs +646 -0
  297. package/packages/engine/tests/runner/api_runner_configs_upsert.rs +651 -0
  298. package/packages/engine/tests/runner/api_runners_list.rs +166 -0
  299. package/packages/engine/tests/runner/api_runners_list_names.rs +386 -0
  300. package/packages/engine/tests/runner/mod.rs +20 -0
  301. package/packages/engine/tests/runner/runner_drain_on_version.rs +620 -0
  302. package/packages/env/Cargo.toml +0 -4
  303. package/packages/env/src/lib.rs +0 -18
  304. package/packages/epoxy/Cargo.toml +3 -2
  305. package/packages/epoxy/README.md +554 -93
  306. package/packages/epoxy/src/consts.rs +4 -36
  307. package/packages/epoxy/src/http_client.rs +59 -26
  308. package/packages/epoxy/src/http_routes.rs +73 -10
  309. package/packages/epoxy/src/keys/keys.rs +260 -11
  310. package/packages/epoxy/src/keys/mod.rs +11 -1
  311. package/packages/epoxy/src/keys/replica.rs +5 -260
  312. package/packages/epoxy/src/lib.rs +2 -1
  313. package/packages/epoxy/src/metrics.rs +118 -0
  314. package/packages/epoxy/src/ops/kv/get_local.rs +15 -24
  315. package/packages/epoxy/src/ops/kv/get_optimistic.rs +102 -64
  316. package/packages/epoxy/src/ops/kv/mod.rs +1 -0
  317. package/packages/epoxy/src/ops/kv/purge_local.rs +18 -9
  318. package/packages/epoxy/src/ops/kv/read_value.rs +92 -0
  319. package/packages/epoxy/src/ops/mod.rs +0 -1
  320. package/packages/epoxy/src/ops/propose.rs +1079 -194
  321. package/packages/epoxy/src/replica/ballot.rs +162 -102
  322. package/packages/epoxy/src/replica/changelog.rs +147 -0
  323. package/packages/epoxy/src/replica/commit_kv.rs +69 -66
  324. package/packages/epoxy/src/replica/message_request.rs +33 -48
  325. package/packages/epoxy/src/replica/messages/accept.rs +82 -41
  326. package/packages/epoxy/src/replica/messages/commit.rs +21 -33
  327. package/packages/epoxy/src/replica/messages/mod.rs +0 -8
  328. package/packages/epoxy/src/replica/messages/prepare.rs +68 -69
  329. package/packages/epoxy/src/replica/mod.rs +1 -6
  330. package/packages/epoxy/src/replica/update_config.rs +3 -1
  331. package/packages/epoxy/src/types.rs +30 -54
  332. package/packages/epoxy/src/utils.rs +149 -16
  333. package/packages/epoxy/src/workflows/backfill.rs +233 -0
  334. package/packages/epoxy/src/workflows/coordinator/mod.rs +33 -7
  335. package/packages/epoxy/src/workflows/coordinator/reconfigure.rs +44 -0
  336. package/packages/epoxy/src/workflows/coordinator/replica_status_change.rs +4 -3
  337. package/packages/epoxy/src/workflows/mod.rs +1 -1
  338. package/packages/epoxy/src/workflows/replica/mod.rs +4 -6
  339. package/packages/epoxy/src/workflows/replica/setup.rs +130 -771
  340. package/packages/epoxy/tests/backfill.rs +65 -0
  341. package/packages/epoxy/tests/backfill_snapshot.rs +233 -0
  342. package/packages/epoxy/tests/common/mod.rs +77 -21
  343. package/packages/epoxy/tests/common/utils.rs +366 -10
  344. package/packages/epoxy/tests/consensus_regressions.rs +285 -0
  345. package/packages/epoxy/tests/kv.rs +128 -167
  346. package/packages/epoxy/tests/kv_get_optimistic.rs +257 -157
  347. package/packages/epoxy/tests/migration.rs +75 -0
  348. package/packages/epoxy/tests/proposal.rs +133 -28
  349. package/packages/epoxy/tests/reconfigure.rs +92 -474
  350. package/packages/error/tests/basic.rs +8 -8
  351. package/packages/gasoline/Cargo.toml +1 -0
  352. package/packages/gasoline/src/builder/common/message.rs +19 -47
  353. package/packages/gasoline/src/builder/common/signal.rs +37 -21
  354. package/packages/gasoline/src/builder/common/workflow.rs +19 -15
  355. package/packages/gasoline/src/builder/workflow/lupe.rs +295 -0
  356. package/packages/gasoline/src/builder/workflow/message.rs +24 -47
  357. package/packages/gasoline/src/builder/workflow/mod.rs +1 -0
  358. package/packages/gasoline/src/builder/workflow/signal.rs +68 -22
  359. package/packages/gasoline/src/builder/workflow/sub_workflow.rs +6 -15
  360. package/packages/gasoline/src/ctx/activity.rs +46 -6
  361. package/packages/gasoline/src/ctx/common.rs +26 -23
  362. package/packages/gasoline/src/ctx/listen.rs +33 -50
  363. package/packages/gasoline/src/ctx/message.rs +76 -64
  364. package/packages/gasoline/src/ctx/operation.rs +15 -5
  365. package/packages/gasoline/src/ctx/standalone.rs +32 -4
  366. package/packages/gasoline/src/ctx/test.rs +31 -6
  367. package/packages/gasoline/src/ctx/versioned_workflow.rs +33 -7
  368. package/packages/gasoline/src/ctx/workflow.rs +194 -384
  369. package/packages/gasoline/src/db/debug.rs +49 -9
  370. package/packages/gasoline/src/db/kv/debug.rs +905 -15
  371. package/packages/gasoline/src/db/kv/keys/history.rs +434 -9
  372. package/packages/gasoline/src/db/kv/keys/metric.rs +70 -47
  373. package/packages/gasoline/src/db/kv/keys/signal.rs +19 -3
  374. package/packages/gasoline/src/db/kv/keys/workflow.rs +349 -3
  375. package/packages/gasoline/src/db/kv/mod.rs +975 -514
  376. package/packages/gasoline/src/db/kv/system.rs +155 -18
  377. package/packages/gasoline/src/db/mod.rs +29 -7
  378. package/packages/gasoline/src/error.rs +26 -21
  379. package/packages/gasoline/src/executable.rs +3 -1
  380. package/packages/gasoline/src/history/cursor.rs +436 -336
  381. package/packages/gasoline/src/history/event.rs +24 -15
  382. package/packages/gasoline/src/listen.rs +2 -14
  383. package/packages/gasoline/src/message.rs +1 -1
  384. package/packages/gasoline/src/metrics.rs +260 -143
  385. package/packages/gasoline/src/prelude.rs +1 -1
  386. package/packages/gasoline/src/registry.rs +6 -2
  387. package/packages/gasoline/src/signal.rs +34 -31
  388. package/packages/gasoline/src/utils/mod.rs +1 -18
  389. package/packages/gasoline/src/utils/topic.rs +35 -0
  390. package/packages/gasoline/src/worker.rs +71 -14
  391. package/packages/gasoline/src/workflow.rs +13 -0
  392. package/packages/gasoline/tests/workflows/eviction_test.rs +2 -2
  393. package/packages/gasoline-macros/src/lib.rs +74 -12
  394. package/packages/gasoline-runtime/Cargo.toml +18 -0
  395. package/packages/gasoline-runtime/src/lib.rs +12 -0
  396. package/packages/gasoline-runtime/src/workflows/mod.rs +1 -0
  397. package/packages/gasoline-runtime/src/workflows/pruner.rs +55 -0
  398. package/packages/guard/Cargo.toml +16 -8
  399. package/packages/guard/src/cache/mod.rs +63 -43
  400. package/packages/guard/src/cache/pegboard_gateway.rs +144 -0
  401. package/packages/guard/src/errors.rs +105 -0
  402. package/packages/guard/src/lib.rs +5 -15
  403. package/packages/guard/src/metrics.rs +12 -0
  404. package/packages/guard/src/routing/actor_path.rs +409 -0
  405. package/packages/guard/src/routing/api_public.rs +6 -14
  406. package/packages/guard/src/routing/envoy.rs +98 -0
  407. package/packages/guard/src/routing/mod.rs +152 -206
  408. package/packages/guard/src/routing/pegboard_gateway/mod.rs +572 -0
  409. package/packages/guard/src/routing/pegboard_gateway/resolve_actor_query.rs +236 -0
  410. package/packages/guard/src/routing/runner.rs +24 -54
  411. package/packages/guard/src/routing/ws_health.rs +61 -0
  412. package/packages/guard/src/shared_state.rs +11 -2
  413. package/packages/guard/tests/parse_actor_path.rs +418 -165
  414. package/packages/guard-core/Cargo.toml +3 -10
  415. package/packages/guard-core/src/custom_serve.rs +4 -10
  416. package/packages/guard-core/src/errors.rs +20 -4
  417. package/packages/guard-core/src/lib.rs +6 -4
  418. package/packages/guard-core/src/metrics.rs +66 -53
  419. package/packages/guard-core/src/proxy_service.rs +618 -1520
  420. package/packages/guard-core/src/request_context.rs +149 -169
  421. package/packages/guard-core/src/response_body.rs +65 -0
  422. package/packages/guard-core/src/route.rs +76 -0
  423. package/packages/guard-core/src/server.rs +60 -26
  424. package/packages/guard-core/src/task_group.rs +4 -0
  425. package/packages/guard-core/src/utils.rs +296 -0
  426. package/packages/guard-core/src/websocket_handle.rs +3 -3
  427. package/packages/guard-core/tests/common/mod.rs +0 -1
  428. package/packages/guard-core/tests/custom_serve.rs +4 -6
  429. package/packages/guard-core/tests/simple_websocket.rs +19 -19
  430. package/packages/guard-core/tests/streaming_response.rs +4 -9
  431. package/packages/metrics/Cargo.toml +3 -2
  432. package/packages/metrics/src/buckets.rs +5 -11
  433. package/packages/metrics/src/lib.rs +6 -3
  434. package/packages/metrics/src/providers.rs +2 -42
  435. package/packages/metrics/src/registry.rs +7 -0
  436. package/packages/metrics/src/server.rs +57 -0
  437. package/packages/namespace/Cargo.toml +0 -3
  438. package/packages/namespace/src/keys/metric.rs +301 -0
  439. package/packages/namespace/src/keys/mod.rs +1 -1
  440. package/packages/namespace/src/ops/get_global.rs +7 -4
  441. package/packages/namespace/src/ops/get_local.rs +32 -16
  442. package/packages/namespace/src/ops/mod.rs +0 -1
  443. package/packages/namespace/src/ops/resolve_for_name_global.rs +7 -4
  444. package/packages/namespace/src/ops/resolve_for_name_local.rs +39 -19
  445. package/packages/namespace/src/workflows/namespace.rs +3 -3
  446. package/packages/pegboard/Cargo.toml +22 -0
  447. package/packages/pegboard/src/actor_kv/entry.rs +47 -0
  448. package/packages/pegboard/src/actor_kv/metrics.rs +19 -0
  449. package/packages/pegboard/src/actor_kv/mod.rs +530 -0
  450. package/packages/pegboard/src/actor_kv/preload.rs +363 -0
  451. package/packages/{actor-kv/src → pegboard/src/actor_kv}/utils.rs +36 -35
  452. package/packages/pegboard/src/errors.rs +39 -5
  453. package/packages/pegboard/src/keys/actor.rs +285 -2
  454. package/packages/{actor-kv/src/entry.rs → pegboard/src/keys/actor_kv.rs} +73 -39
  455. package/packages/pegboard/src/keys/backfill.rs +49 -0
  456. package/packages/pegboard/src/keys/envoy.rs +1070 -0
  457. package/packages/pegboard/src/keys/epoxy/ns.rs +1 -1
  458. package/packages/pegboard/src/keys/mod.rs +4 -6
  459. package/packages/pegboard/src/keys/ns.rs +493 -14
  460. package/packages/pegboard/src/keys/runner.rs +281 -0
  461. package/packages/{namespace → pegboard}/src/keys/runner_config.rs +53 -0
  462. package/packages/pegboard/src/lib.rs +15 -2
  463. package/packages/pegboard/src/metrics.rs +57 -16
  464. package/packages/pegboard/src/ops/actor/create.rs +123 -53
  465. package/packages/pegboard/src/ops/actor/get.rs +14 -45
  466. package/packages/pegboard/src/ops/actor/get_for_gateway.rs +16 -0
  467. package/packages/pegboard/src/ops/actor/get_for_key.rs +3 -0
  468. package/packages/pegboard/src/ops/actor/get_for_kv.rs +43 -0
  469. package/packages/pegboard/src/ops/actor/get_for_runner.rs +99 -0
  470. package/packages/pegboard/src/ops/actor/get_reservation_for_key.rs +1 -0
  471. package/packages/pegboard/src/ops/actor/list_for_ns.rs +10 -38
  472. package/packages/pegboard/src/ops/actor/list_names.rs +3 -3
  473. package/packages/pegboard/src/ops/actor/mod.rs +3 -1
  474. package/packages/pegboard/src/ops/actor/util.rs +263 -0
  475. package/packages/pegboard/src/ops/envoy/drain.rs +101 -0
  476. package/packages/pegboard/src/ops/envoy/evict_actors.rs +54 -0
  477. package/packages/pegboard/src/ops/envoy/expire.rs +92 -0
  478. package/packages/pegboard/src/ops/envoy/get.rs +135 -0
  479. package/packages/pegboard/src/ops/envoy/list.rs +131 -0
  480. package/packages/pegboard/src/ops/envoy/mod.rs +6 -0
  481. package/packages/pegboard/src/ops/envoy/update_ping.rs +92 -0
  482. package/packages/pegboard/src/ops/mod.rs +3 -0
  483. package/packages/pegboard/src/ops/runner/drain.rs +110 -0
  484. package/packages/pegboard/src/ops/runner/list_names.rs +3 -3
  485. package/packages/pegboard/src/ops/runner/list_runner_config_enabled_dcs.rs +199 -0
  486. package/packages/pegboard/src/ops/runner/list_runner_config_epoxy_replica_ids.rs +51 -0
  487. package/packages/pegboard/src/ops/runner/mod.rs +3 -1
  488. package/packages/pegboard/src/ops/runner/update_alloc_idx.rs +17 -5
  489. package/packages/{namespace → pegboard}/src/ops/runner_config/delete.rs +18 -9
  490. package/packages/pegboard/src/ops/runner_config/ensure_normal_if_missing.rs +62 -0
  491. package/packages/{namespace → pegboard}/src/ops/runner_config/get.rs +15 -5
  492. package/packages/pegboard/src/ops/runner_config/get_error.rs +146 -0
  493. package/packages/{namespace → pegboard}/src/ops/runner_config/list.rs +13 -12
  494. package/packages/pegboard/src/ops/runner_config/mod.rs +7 -0
  495. package/packages/pegboard/src/ops/runner_config/refresh_metadata.rs +124 -0
  496. package/packages/pegboard/src/ops/runner_config/upsert.rs +206 -0
  497. package/packages/pegboard/src/ops/serverless_metadata/fetch.rs +223 -0
  498. package/packages/pegboard/src/ops/serverless_metadata/mod.rs +1 -0
  499. package/packages/pegboard/src/pubsub_subjects.rs +52 -0
  500. package/packages/pegboard/src/utils.rs +36 -2
  501. package/packages/pegboard/src/workflows/actor/destroy.rs +135 -99
  502. package/packages/pegboard/src/workflows/actor/keys.rs +59 -5
  503. package/packages/pegboard/src/workflows/actor/metrics.rs +345 -0
  504. package/packages/pegboard/src/workflows/actor/mod.rs +848 -204
  505. package/packages/pegboard/src/workflows/actor/runtime.rs +785 -212
  506. package/packages/pegboard/src/workflows/actor/setup.rs +61 -0
  507. package/packages/pegboard/src/workflows/actor2/keys.rs +337 -0
  508. package/packages/pegboard/src/workflows/actor2/metrics.rs +334 -0
  509. package/packages/pegboard/src/workflows/actor2/mod.rs +1251 -0
  510. package/packages/pegboard/src/workflows/actor2/runtime.rs +1005 -0
  511. package/packages/pegboard/src/workflows/actor_runner_name_selector_backfill.rs +266 -0
  512. package/packages/pegboard/src/workflows/metrics_aggregator.rs +282 -0
  513. package/packages/pegboard/src/workflows/mod.rs +8 -0
  514. package/packages/pegboard/src/workflows/runner.rs +62 -56
  515. package/packages/pegboard/src/workflows/runner2.rs +978 -0
  516. package/packages/pegboard/src/workflows/runner_pool.rs +298 -0
  517. package/packages/pegboard/src/workflows/runner_pool_error_tracker.rs +173 -0
  518. package/packages/pegboard/src/workflows/runner_pool_metadata_poller.rs +237 -0
  519. package/packages/pegboard/src/workflows/serverless/backfill.rs +120 -0
  520. package/packages/pegboard/src/workflows/serverless/conn.rs +702 -0
  521. package/packages/pegboard/src/workflows/serverless/mod.rs +3 -0
  522. package/packages/pegboard/src/workflows/serverless/receiver.rs +87 -0
  523. package/packages/pegboard/tests/actor_v1_pre_migration.rs +77 -0
  524. package/packages/{actor-kv/tests/list_edge_cases.rs → pegboard/tests/kv_list_edge_cases.rs} +74 -59
  525. package/packages/{actor-kv → pegboard}/tests/kv_operations.rs +77 -48
  526. package/packages/pegboard-envoy/Cargo.toml +43 -0
  527. package/packages/pegboard-envoy/src/actor_event_demuxer.rs +165 -0
  528. package/packages/pegboard-envoy/src/conn.rs +417 -0
  529. package/packages/pegboard-envoy/src/errors.rs +38 -0
  530. package/packages/pegboard-envoy/src/lib.rs +250 -0
  531. package/packages/pegboard-envoy/src/metrics.rs +44 -0
  532. package/packages/pegboard-envoy/src/ping_task.rs +61 -0
  533. package/packages/pegboard-envoy/src/tunnel_to_ws_task.rs +183 -0
  534. package/packages/pegboard-envoy/src/utils.rs +68 -0
  535. package/packages/pegboard-envoy/src/ws_to_tunnel_task.rs +536 -0
  536. package/packages/pegboard-envoy/tests/support/ws_to_tunnel_task.rs +82 -0
  537. package/packages/pegboard-gateway/Cargo.toml +2 -0
  538. package/packages/pegboard-gateway/src/keepalive_task.rs +1 -1
  539. package/packages/pegboard-gateway/src/lib.rs +506 -128
  540. package/packages/pegboard-gateway/src/metrics.rs +7 -11
  541. package/packages/pegboard-gateway/src/metrics_task.rs +80 -0
  542. package/packages/pegboard-gateway/src/ping_task.rs +9 -2
  543. package/packages/pegboard-gateway/src/shared_state.rs +110 -74
  544. package/packages/pegboard-gateway/src/tunnel_to_ws_task.rs +21 -7
  545. package/packages/pegboard-gateway/src/ws_to_tunnel_task.rs +12 -6
  546. package/packages/pegboard-gateway2/Cargo.toml +37 -0
  547. package/packages/pegboard-gateway2/src/keepalive_task.rs +61 -0
  548. package/packages/pegboard-gateway2/src/lib.rs +1044 -0
  549. package/packages/pegboard-gateway2/src/metrics.rs +10 -0
  550. package/packages/pegboard-gateway2/src/metrics_task.rs +80 -0
  551. package/packages/pegboard-gateway2/src/ping_task.rs +30 -0
  552. package/packages/pegboard-gateway2/src/shared_state.rs +601 -0
  553. package/packages/pegboard-gateway2/src/tunnel_to_ws_task.rs +99 -0
  554. package/packages/pegboard-gateway2/src/ws_to_tunnel_task.rs +71 -0
  555. package/packages/{pegboard-serverless → pegboard-outbound}/Cargo.toml +9 -9
  556. package/packages/pegboard-outbound/src/lib.rs +487 -0
  557. package/packages/pegboard-outbound/src/metrics.rs +17 -0
  558. package/packages/pegboard-runner/Cargo.toml +11 -5
  559. package/packages/pegboard-runner/src/actor_event_demuxer.rs +163 -0
  560. package/packages/pegboard-runner/src/conn.rs +358 -122
  561. package/packages/pegboard-runner/src/errors.rs +5 -0
  562. package/packages/pegboard-runner/src/lib.rs +62 -36
  563. package/packages/pegboard-runner/src/metrics.rs +44 -0
  564. package/packages/pegboard-runner/src/ping_task.rs +60 -13
  565. package/packages/pegboard-runner/src/tunnel_to_ws_task.rs +249 -110
  566. package/packages/pegboard-runner/src/ws_to_tunnel_task.rs +738 -113
  567. package/packages/pegboard-runner/tests/support/ws_to_tunnel_task.rs +150 -0
  568. package/packages/pools/Cargo.toml +1 -2
  569. package/packages/pools/src/db/clickhouse.rs +7 -6
  570. package/packages/pools/src/db/udb.rs +16 -3
  571. package/packages/pools/src/db/ups.rs +27 -5
  572. package/packages/pools/src/error.rs +0 -3
  573. package/packages/pools/src/lib.rs +0 -2
  574. package/packages/pools/src/metrics.rs +33 -28
  575. package/packages/pools/src/pools.rs +15 -39
  576. package/packages/pools/src/prelude.rs +1 -1
  577. package/packages/postgres-util/Cargo.toml +13 -0
  578. package/packages/postgres-util/src/lib.rs +84 -0
  579. package/packages/runner-protocol/build.rs +157 -0
  580. package/packages/runner-protocol/src/lib.rs +16 -0
  581. package/packages/runner-protocol/src/util.rs +14 -0
  582. package/packages/runner-protocol/src/versioned.rs +4345 -0
  583. package/packages/runtime/src/lib.rs +46 -46
  584. package/packages/runtime/src/metrics.rs +39 -30
  585. package/packages/runtime/src/term_signal.rs +25 -12
  586. package/packages/runtime/src/traces.rs +5 -8
  587. package/packages/service-manager/src/lib.rs +66 -15
  588. package/packages/test-deps/src/datacenter.rs +22 -8
  589. package/packages/test-deps/src/lib.rs +47 -25
  590. package/packages/test-deps-docker/src/database.rs +45 -36
  591. package/packages/test-snapshot-gen/Cargo.toml +39 -0
  592. package/packages/test-snapshot-gen/snapshots/.gitkeep +0 -0
  593. package/packages/test-snapshot-gen/snapshots/epoxy-v1/metadata.json +3 -0
  594. package/packages/test-snapshot-gen/snapshots/epoxy-v1/replica-1/000008.log +0 -0
  595. package/packages/test-snapshot-gen/snapshots/epoxy-v1/replica-1/000009.sst +3 -0
  596. package/packages/test-snapshot-gen/snapshots/epoxy-v1/replica-1/CURRENT +3 -0
  597. package/packages/test-snapshot-gen/snapshots/epoxy-v1/replica-1/MANIFEST-000005 +3 -0
  598. package/packages/test-snapshot-gen/snapshots/epoxy-v1/replica-1/OPTIONS-000007 +3 -0
  599. package/packages/test-snapshot-gen/snapshots/epoxy-v1/replica-2/000008.log +0 -0
  600. package/packages/test-snapshot-gen/snapshots/epoxy-v1/replica-2/000009.sst +3 -0
  601. package/packages/test-snapshot-gen/snapshots/epoxy-v1/replica-2/CURRENT +3 -0
  602. package/packages/test-snapshot-gen/snapshots/epoxy-v1/replica-2/MANIFEST-000005 +3 -0
  603. package/packages/test-snapshot-gen/snapshots/epoxy-v1/replica-2/OPTIONS-000007 +3 -0
  604. package/packages/test-snapshot-gen/snapshots/pb-actor-v1-pre-migration/metadata.json +3 -0
  605. package/packages/test-snapshot-gen/snapshots/pb-actor-v1-pre-migration/replica-1/000008.log +0 -0
  606. package/packages/test-snapshot-gen/snapshots/pb-actor-v1-pre-migration/replica-1/000009.sst +3 -0
  607. package/packages/test-snapshot-gen/snapshots/pb-actor-v1-pre-migration/replica-1/CURRENT +3 -0
  608. package/packages/test-snapshot-gen/snapshots/pb-actor-v1-pre-migration/replica-1/MANIFEST-000005 +3 -0
  609. package/packages/test-snapshot-gen/snapshots/pb-actor-v1-pre-migration/replica-1/OPTIONS-000007 +3 -0
  610. package/packages/test-snapshot-gen/snapshots/pb-actor-v1-pre-migration/replica-2/000008.log +0 -0
  611. package/packages/test-snapshot-gen/snapshots/pb-actor-v1-pre-migration/replica-2/000009.sst +3 -0
  612. package/packages/test-snapshot-gen/snapshots/pb-actor-v1-pre-migration/replica-2/CURRENT +3 -0
  613. package/packages/test-snapshot-gen/snapshots/pb-actor-v1-pre-migration/replica-2/MANIFEST-000005 +3 -0
  614. package/packages/test-snapshot-gen/snapshots/pb-actor-v1-pre-migration/replica-2/OPTIONS-000007 +3 -0
  615. package/packages/test-snapshot-gen/src/lib.rs +328 -0
  616. package/packages/test-snapshot-gen/src/main.rs +145 -0
  617. package/packages/test-snapshot-gen/src/scenarios/epoxy_keys.rs +60 -0
  618. package/packages/test-snapshot-gen/src/scenarios/mod.rs +27 -0
  619. package/packages/test-snapshot-gen/src/scenarios/pb_actor_v1_pre_migration.rs +56 -0
  620. package/packages/test-snapshot-gen/src/test_cluster.rs +234 -0
  621. package/packages/tracing-reconfigure/src/lib.rs +1 -1
  622. package/packages/tracing-utils/src/lib.rs +12 -20
  623. package/packages/types/src/actor/error.rs +59 -0
  624. package/packages/types/src/actor/mod.rs +2 -0
  625. package/packages/types/src/actors.rs +5 -0
  626. package/packages/types/src/envoys.rs +21 -0
  627. package/packages/types/src/keys/backfill.rs +5 -0
  628. package/packages/types/src/keys/mod.rs +1 -0
  629. package/packages/types/src/lib.rs +2 -1
  630. package/packages/types/src/runner_configs.rs +43 -14
  631. package/packages/universaldb/Cargo.toml +4 -0
  632. package/packages/universaldb/src/database.rs +50 -5
  633. package/packages/universaldb/src/driver/mod.rs +12 -2
  634. package/packages/universaldb/src/driver/postgres/database.rs +88 -27
  635. package/packages/universaldb/src/driver/postgres/mod.rs +1 -1
  636. package/packages/universaldb/src/driver/postgres/transaction.rs +4 -7
  637. package/packages/universaldb/src/driver/postgres/transaction_task.rs +30 -52
  638. package/packages/universaldb/src/driver/rocksdb/database.rs +13 -7
  639. package/packages/universaldb/src/driver/rocksdb/transaction_conflict_tracker.rs +5 -5
  640. package/packages/universaldb/src/driver/rocksdb/transaction_task.rs +2 -1
  641. package/packages/universaldb/src/metrics.rs +39 -23
  642. package/packages/universaldb/src/prelude.rs +1 -1
  643. package/packages/universaldb/src/transaction.rs +9 -2
  644. package/packages/universaldb/src/utils/cherry_pick.rs +46 -46
  645. package/packages/universaldb/src/utils/keys.rs +21 -2
  646. package/packages/universaldb/src/utils/mod.rs +8 -0
  647. package/packages/universaldb/src/utils/subspace.rs +9 -4
  648. package/packages/universaldb/tests/integration.rs +5 -3
  649. package/packages/universaldb/tests/integration_gas.rs +5 -3
  650. package/packages/universaldb/tests/rocksdb.rs +152 -19
  651. package/packages/universalpubsub/Cargo.toml +8 -2
  652. package/packages/universalpubsub/benches/simple.rs +28 -8
  653. package/packages/universalpubsub/src/chunking.rs +27 -5
  654. package/packages/universalpubsub/src/driver/memory/mod.rs +131 -20
  655. package/packages/universalpubsub/src/driver/mod.rs +5 -0
  656. package/packages/universalpubsub/src/driver/nats/mod.rs +8 -0
  657. package/packages/universalpubsub/src/driver/postgres/mod.rs +505 -96
  658. package/packages/universalpubsub/src/lib.rs +3 -0
  659. package/packages/universalpubsub/src/metrics.rs +60 -0
  660. package/packages/universalpubsub/src/pubsub.rs +227 -87
  661. package/packages/universalpubsub/src/subject.rs +32 -0
  662. package/packages/universalpubsub/tests/chunking.rs +298 -0
  663. package/packages/universalpubsub/tests/integration.rs +148 -7
  664. package/packages/universalpubsub/tests/reconnect.rs +8 -6
  665. package/packages/util/Cargo.toml +1 -3
  666. package/packages/util/build.rs +6 -0
  667. package/packages/util/src/lib.rs +7 -2
  668. package/packages/util/src/metric.rs +1 -0
  669. package/packages/util/src/serde.rs +1 -516
  670. package/packages/{internal → util-serde}/Cargo.toml +4 -5
  671. package/packages/util-serde/src/lib.rs +517 -0
  672. package/packages/workflow-worker/Cargo.toml +4 -4
  673. package/packages/workflow-worker/src/lib.rs +3 -2
  674. package/sdks/go/api-full/client/client.go +17 -4
  675. package/sdks/go/api-full/metadata/client.go +50 -0
  676. package/sdks/go/api-full/namespaces/client.go +3 -0
  677. package/sdks/go/api-full/namespaces.go +6 -4
  678. package/sdks/go/api-full/runners/client.go +3 -0
  679. package/sdks/go/api-full/runners.go +8 -6
  680. package/sdks/go/api-full/types.go +107 -23
  681. package/sdks/rust/api-full/rust/.openapi-generator/FILES +6 -0
  682. package/sdks/rust/api-full/rust/Cargo.toml +1 -1
  683. package/sdks/rust/api-full/rust/README.md +5 -2
  684. package/sdks/rust/api-full/rust/docs/Actor.md +1 -0
  685. package/sdks/rust/api-full/rust/docs/ActorsDeleteApi.md +1 -1
  686. package/sdks/rust/api-full/rust/docs/ActorsKvGetApi.md +2 -1
  687. package/sdks/rust/api-full/rust/docs/ActorsListApi.md +3 -2
  688. package/sdks/rust/api-full/rust/docs/MetadataApi.md +34 -0
  689. package/sdks/rust/api-full/rust/docs/MetadataGetResponse.md +18 -0
  690. package/sdks/rust/api-full/rust/docs/NamespacesApi.md +3 -2
  691. package/sdks/rust/api-full/rust/docs/RunnerConfig.md +1 -0
  692. package/sdks/rust/api-full/rust/docs/RunnerConfigKindOneOf1Serverless.md +1 -0
  693. package/sdks/rust/api-full/rust/docs/RunnerConfigResponse.md +15 -0
  694. package/sdks/rust/api-full/rust/docs/RunnerConfigsListApi.md +3 -2
  695. package/sdks/rust/api-full/rust/docs/RunnerConfigsListResponseRunnerConfigsValue.md +1 -1
  696. package/sdks/rust/api-full/rust/docs/RunnersApi.md +3 -2
  697. package/sdks/rust/api-full/rust/src/apis/actors_create_api.rs +1 -1
  698. package/sdks/rust/api-full/rust/src/apis/actors_delete_api.rs +3 -5
  699. package/sdks/rust/api-full/rust/src/apis/actors_get_or_create_api.rs +1 -1
  700. package/sdks/rust/api-full/rust/src/apis/actors_kv_get_api.rs +4 -2
  701. package/sdks/rust/api-full/rust/src/apis/actors_list_api.rs +9 -2
  702. package/sdks/rust/api-full/rust/src/apis/actors_list_names_api.rs +1 -1
  703. package/sdks/rust/api-full/rust/src/apis/configuration.rs +2 -2
  704. package/sdks/rust/api-full/rust/src/apis/datacenters_api.rs +1 -1
  705. package/sdks/rust/api-full/rust/src/apis/health_api.rs +1 -1
  706. package/sdks/rust/api-full/rust/src/apis/metadata_api.rs +62 -0
  707. package/sdks/rust/api-full/rust/src/apis/mod.rs +1 -0
  708. package/sdks/rust/api-full/rust/src/apis/namespaces_api.rs +9 -2
  709. package/sdks/rust/api-full/rust/src/apis/runner_configs_delete_api.rs +1 -1
  710. package/sdks/rust/api-full/rust/src/apis/runner_configs_list_api.rs +9 -2
  711. package/sdks/rust/api-full/rust/src/apis/runner_configs_refresh_metadata_api.rs +1 -1
  712. package/sdks/rust/api-full/rust/src/apis/runner_configs_serverless_health_check_api.rs +1 -1
  713. package/sdks/rust/api-full/rust/src/apis/runner_configs_upsert_api.rs +1 -1
  714. package/sdks/rust/api-full/rust/src/apis/runners_api.rs +9 -2
  715. package/sdks/rust/api-full/rust/src/models/actor.rs +5 -1
  716. package/sdks/rust/api-full/rust/src/models/actor_name.rs +1 -1
  717. package/sdks/rust/api-full/rust/src/models/actors_create_request.rs +1 -1
  718. package/sdks/rust/api-full/rust/src/models/actors_create_response.rs +1 -1
  719. package/sdks/rust/api-full/rust/src/models/actors_get_or_create_request.rs +1 -1
  720. package/sdks/rust/api-full/rust/src/models/actors_get_or_create_response.rs +1 -1
  721. package/sdks/rust/api-full/rust/src/models/actors_kv_get_response.rs +1 -1
  722. package/sdks/rust/api-full/rust/src/models/actors_list_names_response.rs +1 -1
  723. package/sdks/rust/api-full/rust/src/models/actors_list_response.rs +1 -1
  724. package/sdks/rust/api-full/rust/src/models/crash_policy.rs +1 -1
  725. package/sdks/rust/api-full/rust/src/models/datacenter.rs +1 -1
  726. package/sdks/rust/api-full/rust/src/models/datacenter_health.rs +1 -1
  727. package/sdks/rust/api-full/rust/src/models/datacenters_list_response.rs +1 -1
  728. package/sdks/rust/api-full/rust/src/models/health_fanout_response.rs +1 -1
  729. package/sdks/rust/api-full/rust/src/models/health_response.rs +1 -1
  730. package/sdks/rust/api-full/rust/src/models/health_status.rs +1 -1
  731. package/sdks/rust/api-full/rust/src/models/metadata_get_response.rs +48 -0
  732. package/sdks/rust/api-full/rust/src/models/mod.rs +4 -0
  733. package/sdks/rust/api-full/rust/src/models/namespace.rs +1 -1
  734. package/sdks/rust/api-full/rust/src/models/namespace_list_response.rs +1 -1
  735. package/sdks/rust/api-full/rust/src/models/namespaces_create_request.rs +1 -1
  736. package/sdks/rust/api-full/rust/src/models/namespaces_create_response.rs +1 -1
  737. package/sdks/rust/api-full/rust/src/models/pagination.rs +1 -1
  738. package/sdks/rust/api-full/rust/src/models/runner.rs +1 -1
  739. package/sdks/rust/api-full/rust/src/models/runner_config.rs +4 -1
  740. package/sdks/rust/api-full/rust/src/models/runner_config_kind.rs +1 -1
  741. package/sdks/rust/api-full/rust/src/models/runner_config_kind_one_of.rs +1 -1
  742. package/sdks/rust/api-full/rust/src/models/runner_config_kind_one_of_1.rs +1 -1
  743. package/sdks/rust/api-full/rust/src/models/runner_config_kind_one_of_1_serverless.rs +5 -1
  744. package/sdks/rust/api-full/rust/src/models/runner_config_response.rs +39 -0
  745. package/sdks/rust/api-full/rust/src/models/runner_config_variant.rs +1 -1
  746. package/sdks/rust/api-full/rust/src/models/runner_configs_list_response.rs +1 -1
  747. package/sdks/rust/api-full/rust/src/models/runner_configs_list_response_runner_configs_value.rs +3 -3
  748. package/sdks/rust/api-full/rust/src/models/runner_configs_serverless_health_check_request.rs +1 -1
  749. package/sdks/rust/api-full/rust/src/models/runner_configs_serverless_health_check_response.rs +1 -1
  750. package/sdks/rust/api-full/rust/src/models/runner_configs_serverless_health_check_response_one_of.rs +1 -1
  751. package/sdks/rust/api-full/rust/src/models/runner_configs_serverless_health_check_response_one_of_1.rs +1 -1
  752. package/sdks/rust/api-full/rust/src/models/runner_configs_serverless_health_check_response_one_of_1_failure.rs +1 -1
  753. package/sdks/rust/api-full/rust/src/models/runner_configs_serverless_health_check_response_one_of_success.rs +1 -1
  754. package/sdks/rust/api-full/rust/src/models/runner_configs_serverless_metadata_error.rs +1 -1
  755. package/sdks/rust/api-full/rust/src/models/runner_configs_serverless_metadata_error_one_of.rs +1 -1
  756. package/sdks/rust/api-full/rust/src/models/runner_configs_serverless_metadata_error_one_of_1.rs +1 -1
  757. package/sdks/rust/api-full/rust/src/models/runner_configs_serverless_metadata_error_one_of_2.rs +1 -1
  758. package/sdks/rust/api-full/rust/src/models/runner_configs_serverless_metadata_error_one_of_3.rs +1 -1
  759. package/sdks/rust/api-full/rust/src/models/runner_configs_serverless_metadata_error_one_of_3_non_success_status.rs +1 -1
  760. package/sdks/rust/api-full/rust/src/models/runner_configs_serverless_metadata_error_one_of_4.rs +1 -1
  761. package/sdks/rust/api-full/rust/src/models/runner_configs_serverless_metadata_error_one_of_4_invalid_response_json.rs +1 -1
  762. package/sdks/rust/api-full/rust/src/models/runner_configs_serverless_metadata_error_one_of_5.rs +1 -1
  763. package/sdks/rust/api-full/rust/src/models/runner_configs_serverless_metadata_error_one_of_5_invalid_response_schema.rs +1 -1
  764. package/sdks/rust/api-full/rust/src/models/runner_configs_upsert_request_body.rs +1 -1
  765. package/sdks/rust/api-full/rust/src/models/runner_configs_upsert_response.rs +1 -1
  766. package/sdks/rust/api-full/rust/src/models/runners_list_names_response.rs +1 -1
  767. package/sdks/rust/api-full/rust/src/models/runners_list_response.rs +1 -1
  768. package/sdks/rust/api-full/src/apis/actors_api.rs +8 -4
  769. package/sdks/rust/api-full/src/apis/ns_api.rs +8 -4
  770. package/sdks/rust/data/src/converted.rs +7 -4
  771. package/sdks/rust/data/src/lib.rs +2 -2
  772. package/sdks/rust/data/src/versioned/mod.rs +47 -4
  773. package/sdks/rust/data/src/versioned/namespace_runner_config.rs +256 -6
  774. package/sdks/rust/envoy-client/Cargo.toml +25 -0
  775. package/sdks/rust/envoy-client/src/actor.rs +992 -0
  776. package/sdks/rust/envoy-client/src/commands.rs +88 -0
  777. package/sdks/rust/envoy-client/src/config.rs +159 -0
  778. package/sdks/rust/envoy-client/src/connection.rs +288 -0
  779. package/sdks/rust/envoy-client/src/context.rs +24 -0
  780. package/sdks/rust/envoy-client/src/envoy.rs +432 -0
  781. package/sdks/rust/envoy-client/src/events.rs +62 -0
  782. package/sdks/rust/envoy-client/src/handle.rs +355 -0
  783. package/sdks/rust/envoy-client/src/kv.rs +132 -0
  784. package/sdks/rust/envoy-client/src/latency_channel.rs +27 -0
  785. package/sdks/rust/envoy-client/src/lib.rs +15 -0
  786. package/sdks/rust/envoy-client/src/stringify.rs +322 -0
  787. package/sdks/rust/envoy-client/src/tunnel.rs +265 -0
  788. package/sdks/rust/envoy-client/src/utils.rs +172 -0
  789. package/sdks/rust/envoy-protocol/Cargo.toml +22 -0
  790. package/sdks/rust/envoy-protocol/build.rs +200 -0
  791. package/sdks/rust/envoy-protocol/src/generated.rs +1 -0
  792. package/sdks/rust/envoy-protocol/src/lib.rs +8 -0
  793. package/sdks/rust/envoy-protocol/src/versioned.rs +208 -0
  794. package/sdks/rust/epoxy-protocol/Cargo.toml +0 -2
  795. package/sdks/rust/epoxy-protocol/build.rs +7 -0
  796. package/sdks/rust/epoxy-protocol/src/lib.rs +2 -5
  797. package/sdks/rust/epoxy-protocol/src/protocol.rs +128 -0
  798. package/sdks/rust/test-envoy/Cargo.toml +23 -0
  799. package/sdks/rust/test-envoy/Dockerfile +22 -0
  800. package/sdks/rust/test-envoy/src/behaviors.rs +141 -0
  801. package/sdks/rust/test-envoy/src/lib.rs +11 -0
  802. package/sdks/rust/test-envoy/src/main.rs +4 -0
  803. package/sdks/rust/test-envoy/src/server.rs +269 -0
  804. package/sdks/schemas/README.md +1 -2
  805. package/sdks/schemas/data/namespace.runner_config.v3.bare +24 -0
  806. package/sdks/schemas/data/namespace.runner_config.v4.bare +25 -0
  807. package/sdks/schemas/data/namespace.runner_config.v5.bare +26 -0
  808. package/sdks/schemas/data/pegboard.namespace.runner_alloc_idx.v2.bare +8 -0
  809. package/sdks/schemas/envoy-protocol/v1.bare +459 -0
  810. package/sdks/schemas/epoxy-protocol/v2.bare +220 -0
  811. package/sdks/schemas/runner-protocol/v4.bare +438 -0
  812. package/sdks/schemas/runner-protocol/v5.bare +430 -0
  813. package/sdks/schemas/runner-protocol/v6.bare +432 -0
  814. package/sdks/schemas/runner-protocol/v7.bare +438 -0
  815. package/sdks/typescript/api-full/.turbo/turbo-build.log +28 -27
  816. package/sdks/typescript/api-full/build.js +7 -1
  817. package/sdks/typescript/api-full/package.json +66 -57
  818. package/sdks/typescript/api-full/rivetkit-engine-api-full-25.5.3.tgz +0 -0
  819. package/sdks/typescript/api-full/src/Client.ts +41 -10
  820. package/sdks/typescript/api-full/src/api/client/requests/ActorsDeleteRequest.ts +4 -2
  821. package/sdks/typescript/api-full/src/api/client/requests/ActorsKvGetRequest.ts +13 -0
  822. package/sdks/typescript/api-full/src/api/client/requests/ActorsListRequest.ts +6 -0
  823. package/sdks/typescript/api-full/src/api/client/requests/RunnerConfigsListRequest.ts +4 -0
  824. package/sdks/typescript/api-full/src/api/client/requests/index.ts +1 -0
  825. package/sdks/typescript/api-full/src/api/resources/index.ts +1 -0
  826. package/sdks/typescript/api-full/src/api/resources/metadata/client/Client.ts +97 -0
  827. package/sdks/typescript/api-full/src/api/resources/metadata/client/index.ts +1 -0
  828. package/sdks/typescript/api-full/src/api/resources/metadata/index.ts +1 -0
  829. package/sdks/typescript/api-full/src/api/resources/namespaces/client/Client.ts +12 -2
  830. package/sdks/typescript/api-full/src/api/resources/namespaces/client/requests/NamespacesListRequest.ts +6 -0
  831. package/sdks/typescript/api-full/src/api/resources/runners/client/Client.ts +12 -2
  832. package/sdks/typescript/api-full/src/api/resources/runners/client/requests/RunnersListRequest.ts +6 -0
  833. package/sdks/typescript/api-full/src/api/types/Actor.ts +2 -0
  834. package/sdks/typescript/api-full/src/api/types/MetadataGetResponse.ts +14 -0
  835. package/sdks/typescript/api-full/src/api/types/RunnerConfig.ts +1 -0
  836. package/sdks/typescript/api-full/src/api/types/RunnerConfigKindServerlessServerless.ts +2 -0
  837. package/sdks/typescript/api-full/src/api/types/RunnerConfigResponse.ts +9 -0
  838. package/sdks/typescript/api-full/src/api/types/RunnerConfigServerless.ts +2 -0
  839. package/sdks/typescript/api-full/src/api/types/RunnerConfigsListResponseRunnerConfigsValue.ts +1 -1
  840. package/sdks/typescript/api-full/src/api/types/index.ts +2 -0
  841. package/sdks/typescript/api-full/src/core/fetcher/stream-wrappers/Node18UniversalStreamWrapper.ts +6 -4
  842. package/sdks/typescript/api-full/src/core/fetcher/stream-wrappers/UndiciStreamWrapper.ts +4 -3
  843. package/sdks/typescript/api-full/src/serialization/types/Actor.ts +2 -0
  844. package/sdks/typescript/api-full/src/serialization/types/MetadataGetResponse.ts +34 -0
  845. package/sdks/typescript/api-full/src/serialization/types/RunnerConfig.ts +5 -0
  846. package/sdks/typescript/api-full/src/serialization/types/RunnerConfigKindServerlessServerless.ts +2 -0
  847. package/sdks/typescript/api-full/src/serialization/types/RunnerConfigResponse.ts +26 -0
  848. package/sdks/typescript/api-full/src/serialization/types/RunnerConfigServerless.ts +2 -0
  849. package/sdks/typescript/api-full/src/serialization/types/RunnerConfigsListResponseRunnerConfigsValue.ts +3 -3
  850. package/sdks/typescript/api-full/src/serialization/types/index.ts +2 -0
  851. package/sdks/typescript/api-full/turbo.json +9 -0
  852. package/sdks/typescript/envoy-protocol/.turbo/turbo-build.log +23 -0
  853. package/sdks/typescript/{runner-protocol → envoy-protocol}/dist/index.cjs +466 -281
  854. package/sdks/typescript/envoy-protocol/dist/index.cjs.map +1 -0
  855. package/sdks/typescript/envoy-protocol/dist/index.d.cts +699 -0
  856. package/sdks/typescript/envoy-protocol/dist/index.d.ts +699 -0
  857. package/sdks/typescript/{runner-protocol → envoy-protocol}/dist/index.js +530 -345
  858. package/sdks/typescript/envoy-protocol/dist/index.js.map +1 -0
  859. package/sdks/typescript/{runner-protocol → envoy-protocol}/node_modules/.bin/tsc +4 -4
  860. package/{tests/load → sdks/typescript/envoy-protocol}/node_modules/.bin/tsserver +4 -4
  861. package/sdks/typescript/envoy-protocol/node_modules/.bin/tsup +21 -0
  862. package/sdks/typescript/envoy-protocol/node_modules/.bin/tsup-node +21 -0
  863. package/sdks/typescript/envoy-protocol/package.json +36 -0
  864. package/sdks/typescript/envoy-protocol/src/index.ts +2331 -0
  865. package/sdks/typescript/envoy-protocol/tsconfig.json +9 -0
  866. package/sdks/typescript/envoy-protocol/tsup.config.ts +4 -0
  867. package/sdks/typescript/runner/package.json +8 -2
  868. package/sdks/typescript/runner/src/actor.ts +38 -0
  869. package/sdks/typescript/runner/src/mod.ts +435 -229
  870. package/sdks/typescript/runner/src/stringify.ts +36 -33
  871. package/sdks/typescript/runner/src/tunnel.ts +52 -56
  872. package/sdks/typescript/runner/src/utils.ts +19 -0
  873. package/sdks/typescript/runner/src/websocket-tunnel-adapter.ts +98 -435
  874. package/sdks/typescript/runner-protocol/package.json +11 -9
  875. package/sdks/typescript/runner-protocol/src/index.ts +224 -156
  876. package/sdks/typescript/runner-protocol/tsconfig.json +1 -9
  877. package/sdks/typescript/test-runner/.turbo/turbo-build.log +5 -5
  878. package/sdks/typescript/test-runner/dist/index.js +53 -44
  879. package/sdks/typescript/test-runner/dist/index.js.map +1 -1
  880. package/sdks/typescript/test-runner/node_modules/.bin/pino +2 -2
  881. package/sdks/typescript/test-runner/node_modules/.bin/tsc +4 -4
  882. package/sdks/typescript/test-runner/node_modules/.bin/tsserver +4 -4
  883. package/sdks/typescript/test-runner/node_modules/.bin/tsup +4 -4
  884. package/sdks/typescript/test-runner/node_modules/.bin/tsup-node +4 -4
  885. package/sdks/typescript/test-runner/node_modules/.bin/tsx +4 -4
  886. package/sdks/typescript/test-runner/node_modules/.bin/vitest +4 -4
  887. package/sdks/typescript/test-runner/package.json +3 -3
  888. package/sdks/typescript/test-runner/src/index.ts +65 -42
  889. package/sdks/typescript/test-runner/src/log.ts +4 -18
  890. package/artifacts/errors/actor.no_runners_available.json +0 -5
  891. package/artifacts/errors/guard.actor_destroyed.json +0 -5
  892. package/artifacts/errors/guard.actor_not_found.json +0 -5
  893. package/contrib-docs/ACTOR_KEY_RESERVATION.md +0 -101
  894. package/contrib-docs/API.md +0 -11
  895. package/contrib-docs/DOCKER.md +0 -5
  896. package/contrib-docs/ERRORS.md +0 -13
  897. package/contrib-docs/GUARD.md +0 -76
  898. package/contrib-docs/PEGBOARD_TUNNEL_RETRIES.md +0 -83
  899. package/contrib-docs/RUNNER_LIFECYCLE.md +0 -172
  900. package/contrib-docs/SDKS.md +0 -9
  901. package/contrib-docs/TEST_DEPENDENCIES.md +0 -43
  902. package/contrib-docs/design-choicse/EMBEDDED_KV.md +0 -80
  903. package/contrib-docs/operate/TRACING_RECONFIGURE.md +0 -78
  904. package/docker/dev/otel-collector-client/config.yaml +0 -39
  905. package/docker/dev-host/otel-collector-client/config.yaml +0 -39
  906. package/docker/dev-multidc/datacenters/dc-a/otel-collector-client/config.yaml +0 -39
  907. package/docker/dev-multidc/datacenters/dc-b/otel-collector-client/config.yaml +0 -39
  908. package/docker/dev-multidc/datacenters/dc-c/otel-collector-client/config.yaml +0 -39
  909. package/docker/dev-multidc-multinode/datacenters/dc-a/otel-collector-client/config.yaml +0 -39
  910. package/docker/dev-multidc-multinode/datacenters/dc-b/otel-collector-client/config.yaml +0 -39
  911. package/docker/dev-multidc-multinode/datacenters/dc-c/otel-collector-client/config.yaml +0 -39
  912. package/docker/dev-multinode/otel-collector-client/config.yaml +0 -39
  913. package/docker/template/src/services/edge/otel-collector-client.ts +0 -64
  914. package/packages/actor-kv/Cargo.toml +0 -31
  915. package/packages/actor-kv/src/key.rs +0 -81
  916. package/packages/actor-kv/src/lib.rs +0 -357
  917. package/packages/cache/src/rate_limit.rs +0 -109
  918. package/packages/cache/tests/integration.rs +0 -582
  919. package/packages/clickhouse-inserter/Cargo.toml +0 -17
  920. package/packages/clickhouse-inserter/src/error.rs +0 -16
  921. package/packages/clickhouse-inserter/src/lib.rs +0 -179
  922. package/packages/clickhouse-user-query/Cargo.toml +0 -16
  923. package/packages/clickhouse-user-query/examples/case_sensitivity_demo.rs +0 -100
  924. package/packages/clickhouse-user-query/examples/group_by_example.rs +0 -53
  925. package/packages/clickhouse-user-query/examples/string_contains_demo.rs +0 -96
  926. package/packages/clickhouse-user-query/src/builder.rs +0 -445
  927. package/packages/clickhouse-user-query/src/error.rs +0 -37
  928. package/packages/clickhouse-user-query/src/lib.rs +0 -61
  929. package/packages/clickhouse-user-query/src/query.rs +0 -143
  930. package/packages/clickhouse-user-query/src/schema.rs +0 -78
  931. package/packages/clickhouse-user-query/tests/builder_tests.rs +0 -619
  932. package/packages/clickhouse-user-query/tests/case_sensitivity_tests.rs +0 -307
  933. package/packages/clickhouse-user-query/tests/integration_tests.rs +0 -540
  934. package/packages/clickhouse-user-query/tests/query_tests.rs +0 -263
  935. package/packages/clickhouse-user-query/tests/schema_tests.rs +0 -44
  936. package/packages/config/src/config/vector.rs +0 -18
  937. package/packages/engine/src/commands/udb_keys.rs +0 -200
  938. package/packages/engine/tests/actors_create.rs +0 -524
  939. package/packages/engine/tests/actors_delete.rs +0 -243
  940. package/packages/engine/tests/actors_general.rs +0 -191
  941. package/packages/engine/tests/actors_get.rs +0 -230
  942. package/packages/engine/tests/actors_get_by_id.rs +0 -170
  943. package/packages/engine/tests/actors_get_or_create.rs +0 -294
  944. package/packages/engine/tests/actors_get_or_create_by_id.rs +0 -147
  945. package/packages/engine/tests/actors_lifecycle.rs +0 -165
  946. package/packages/engine/tests/actors_list.rs +0 -798
  947. package/packages/engine/tests/actors_list_names.rs +0 -353
  948. package/packages/engine/tests/common/ns.rs +0 -36
  949. package/packages/engine/tests/common/runner.rs +0 -134
  950. package/packages/engine/tests/runners_dupe_key.rs +0 -27
  951. package/packages/engine/tests/runners_version.rs +0 -50
  952. package/packages/env/build.rs +0 -8
  953. package/packages/epoxy/spec/KEYS.md +0 -33
  954. package/packages/epoxy/spec/PROPOSAL.md +0 -125
  955. package/packages/epoxy/spec/RECONFIGURE.md +0 -40
  956. package/packages/epoxy/src/ops/explicit_prepare.rs +0 -342
  957. package/packages/epoxy/src/replica/decide_path.rs +0 -51
  958. package/packages/epoxy/src/replica/lead_consensus.rs +0 -65
  959. package/packages/epoxy/src/replica/log.rs +0 -84
  960. package/packages/epoxy/src/replica/messages/accepted.rs +0 -35
  961. package/packages/epoxy/src/replica/messages/committed.rs +0 -41
  962. package/packages/epoxy/src/replica/messages/download_instances.rs +0 -69
  963. package/packages/epoxy/src/replica/messages/pre_accept.rs +0 -69
  964. package/packages/epoxy/src/replica/utils.rs +0 -111
  965. package/packages/epoxy/src/workflows/purger.rs +0 -81
  966. package/packages/guard/src/cache/actor.rs +0 -43
  967. package/packages/guard/src/middleware.rs +0 -42
  968. package/packages/guard/src/routing/pegboard_gateway.rs +0 -260
  969. package/packages/guard-core/src/analytics.rs +0 -46
  970. package/packages/internal/README.md +0 -1
  971. package/packages/internal/src/lib.rs +0 -1
  972. package/packages/internal/src/ops/bump_serverless_autoscaler_global.rs +0 -64
  973. package/packages/internal/src/ops/cache/mod.rs +0 -1
  974. package/packages/internal/src/ops/cache/purge_global.rs +0 -81
  975. package/packages/internal/src/ops/mod.rs +0 -2
  976. package/packages/namespace/src/ops/runner_config/mod.rs +0 -4
  977. package/packages/namespace/src/ops/runner_config/upsert.rs +0 -148
  978. package/packages/pegboard/src/ops/actor/get_runner.rs +0 -64
  979. package/packages/pegboard/src/ops/runner/find_dc_with_runner.rs +0 -222
  980. package/packages/pegboard-serverless/src/lib.rs +0 -523
  981. package/packages/types/src/msgs/mod.rs +0 -1
  982. package/packages/types/src/msgs/pegboard.rs +0 -5
  983. package/sdks/rust/epoxy-protocol/src/versioned.rs +0 -206
  984. package/sdks/rust/runner-protocol/build.rs +0 -115
  985. package/sdks/rust/runner-protocol/src/lib.rs +0 -10
  986. package/sdks/rust/runner-protocol/src/versioned.rs +0 -1734
  987. package/sdks/schemas/epoxy-protocol/v1.bare +0 -260
  988. package/sdks/typescript/runner/.turbo/turbo-build.log +0 -22
  989. package/sdks/typescript/runner/dist/mod.cjs +0 -2951
  990. package/sdks/typescript/runner/dist/mod.cjs.map +0 -1
  991. package/sdks/typescript/runner/dist/mod.d.cts +0 -326
  992. package/sdks/typescript/runner/dist/mod.d.ts +0 -326
  993. package/sdks/typescript/runner/dist/mod.js +0 -2951
  994. package/sdks/typescript/runner/dist/mod.js.map +0 -1
  995. package/sdks/typescript/runner/node_modules/.bin/pino +0 -21
  996. package/sdks/typescript/runner/node_modules/.bin/tsc +0 -21
  997. package/sdks/typescript/runner/node_modules/.bin/tsserver +0 -21
  998. package/sdks/typescript/runner/node_modules/.bin/tsup +0 -21
  999. package/sdks/typescript/runner/node_modules/.bin/tsup-node +0 -21
  1000. package/sdks/typescript/runner/node_modules/.bin/tsx +0 -21
  1001. package/sdks/typescript/runner/node_modules/.bin/uuid +0 -21
  1002. package/sdks/typescript/runner/node_modules/.bin/vitest +0 -21
  1003. package/sdks/typescript/runner-protocol/.turbo/turbo-build.log +0 -22
  1004. package/sdks/typescript/runner-protocol/dist/index.cjs.map +0 -1
  1005. package/sdks/typescript/runner-protocol/dist/index.d.cts +0 -666
  1006. package/sdks/typescript/runner-protocol/dist/index.d.ts +0 -666
  1007. package/sdks/typescript/runner-protocol/dist/index.js.map +0 -1
  1008. package/sdks/typescript/runner-protocol/node_modules/.bin/tsserver +0 -21
  1009. package/sdks/typescript/runner-protocol/node_modules/.bin/tsup +0 -21
  1010. package/sdks/typescript/runner-protocol/node_modules/.bin/tsup-node +0 -21
  1011. package/sdks/typescript/test-runner/Dockerfile +0 -26
  1012. package/tests/load/README.md +0 -28
  1013. package/tests/load/actor-lifecycle/README.md +0 -26
  1014. package/tests/load/actor-lifecycle/actor.ts +0 -41
  1015. package/tests/load/actor-lifecycle/config.ts +0 -14
  1016. package/tests/load/actor-lifecycle/index.ts +0 -62
  1017. package/tests/load/actor-lifecycle/rivet_api.ts +0 -140
  1018. package/tests/load/actor-lifecycle/types.ts +0 -17
  1019. package/tests/load/node_modules/.bin/biome +0 -21
  1020. package/tests/load/node_modules/.bin/tsc +0 -21
  1021. package/tests/load/package.json +0 -15
  1022. package/tests/load/tsconfig.json +0 -20
  1023. package/tests/smoke/README.md +0 -32
  1024. package/tests/smoke/package.json +0 -19
  1025. package/tests/smoke/scripts/connect.ts +0 -41
  1026. package/tests/smoke/src/server/registry.ts +0 -32
  1027. package/tests/smoke/src/server/server.ts +0 -7
  1028. package/tests/smoke/src/smoke-test/index.ts +0 -161
  1029. package/tests/smoke/src/smoke-test/spawn-actor.ts +0 -109
  1030. package/tests/smoke/tsconfig.json +0 -43
  1031. /package/packages/{dump-openapi → api-public-openapi-gen}/build.rs +0 -0
  1032. /package/packages/{dump-openapi → api-public-openapi-gen}/src/lib.rs +0 -0
  1033. /package/{sdks/rust → packages}/runner-protocol/Cargo.toml +0 -0
  1034. /package/{sdks/rust → packages}/runner-protocol/src/compat.rs +0 -0
  1035. /package/{sdks/rust → packages}/runner-protocol/src/generated.rs +0 -0
  1036. /package/{sdks/rust → packages}/runner-protocol/src/uuid_compat.rs +0 -0
  1037. /package/sdks/rust/{runner-protocol → envoy-protocol}/src/util.rs +0 -0
  1038. /package/{tests/smoke → sdks/typescript/envoy-protocol}/turbo.json +0 -0
@@ -1,358 +1,66 @@
1
1
  use anyhow::{Context, Result, bail, ensure};
2
2
  use bytes::Bytes;
3
3
  use futures_util::{SinkExt, StreamExt};
4
- use http_body_util::{BodyExt, Full};
5
- use hyper::{Request, Response, StatusCode, body::Incoming as BodyIncoming, header::HeaderName};
4
+ use http_body_util::{BodyExt, Full, Limited};
5
+ use hyper::{
6
+ Request, Response, StatusCode,
7
+ body::Incoming as BodyIncoming,
8
+ header::{HeaderName, HeaderValue},
9
+ };
6
10
  use hyper_tungstenite;
7
11
  use hyper_util::{client::legacy::Client, rt::TokioExecutor};
8
12
  use moka::future::Cache;
9
- use rand;
10
- use rivet_api_builder::{ErrorResponse, RawErrorResponse};
13
+ use rand::seq::SliceRandom;
11
14
  use rivet_api_builder::{RequestIds, X_RIVET_RAY_ID};
12
- use rivet_error::{INTERNAL_ERROR, RivetError};
13
- use rivet_metrics::KeyValue;
14
15
  use rivet_util::Id;
15
- use serde_json;
16
+ use tracing_opentelemetry::OpenTelemetrySpanExt;
16
17
 
17
18
  use rivet_runner_protocol as protocol;
18
19
  use std::{
19
- borrow::Cow,
20
- collections::{HashMap as StdHashMap, HashSet},
21
- net::SocketAddr,
20
+ net::{IpAddr, SocketAddr},
22
21
  sync::Arc,
23
22
  time::{Duration, Instant},
24
23
  };
25
24
  use tokio::sync::Mutex;
26
25
  use tokio::time::timeout;
27
- use tokio_tungstenite::tungstenite::{
28
- client::IntoClientRequest,
29
- protocol::{CloseFrame, frame::coding::CloseCode},
30
- };
26
+ use tokio_tungstenite::tungstenite::client::IntoClientRequest;
31
27
  use tracing::Instrument;
32
28
  use url::Url;
33
29
 
30
+ use crate::RouteTarget;
31
+ use crate::request_context::RequestContext;
32
+ use crate::response_body::ResponseBody;
33
+ use crate::route::{
34
+ CacheKeyFn, DEFAULT_ROUTE_TIMEOUT, ResolveRouteOutput, RouteCache, RoutingFn, RoutingOutput,
35
+ };
36
+ use crate::utils::{InFlightCounter, RateLimiter};
34
37
  use crate::{
35
- WebSocketHandle,
36
- custom_serve::{CustomServeTrait, HibernationResult},
37
- errors, metrics,
38
- request_context::RequestContext,
39
- task_group::TaskGroup,
38
+ WebSocketHandle, custom_serve::HibernationResult, errors, metrics, task_group::TaskGroup, utils,
40
39
  };
41
40
 
42
- const X_RIVET_TARGET: HeaderName = HeaderName::from_static("x-rivet-target");
43
- const X_RIVET_ACTOR: HeaderName = HeaderName::from_static("x-rivet-actor");
44
- const X_RIVET_TOKEN: HeaderName = HeaderName::from_static("x-rivet-token");
45
41
  pub const X_FORWARDED_FOR: HeaderName = HeaderName::from_static("x-forwarded-for");
46
42
  pub const X_RIVET_ERROR: HeaderName = HeaderName::from_static("x-rivet-error");
47
43
 
48
- const ROUTE_CACHE_TTL: Duration = Duration::from_secs(60 * 10); // 10 minutes
49
44
  const PROXY_STATE_CACHE_TTL: Duration = Duration::from_secs(60 * 60); // 1 hour
50
45
  const WEBSOCKET_CLOSE_LINGER: Duration = Duration::from_millis(100); // Keep TCP connection open briefly after WebSocket close
51
46
 
52
- /// Response body type that can handle both streaming and buffered responses
53
- #[derive(Debug)]
54
- pub enum ResponseBody {
55
- /// Buffered response body
56
- Full(Full<Bytes>),
57
- /// Streaming response body
58
- Incoming(BodyIncoming),
59
- }
60
-
61
- impl http_body::Body for ResponseBody {
62
- type Data = Bytes;
63
- type Error = Box<dyn std::error::Error + Send + Sync>;
64
-
65
- fn poll_frame(
66
- self: std::pin::Pin<&mut Self>,
67
- cx: &mut std::task::Context<'_>,
68
- ) -> std::task::Poll<Option<Result<http_body::Frame<Self::Data>, Self::Error>>> {
69
- match self.get_mut() {
70
- ResponseBody::Full(body) => {
71
- let pin = std::pin::Pin::new(body);
72
- match pin.poll_frame(cx) {
73
- std::task::Poll::Ready(Some(Ok(frame))) => {
74
- std::task::Poll::Ready(Some(Ok(frame)))
75
- }
76
- std::task::Poll::Ready(Some(Err(e))) => {
77
- std::task::Poll::Ready(Some(Err(Box::new(e))))
78
- }
79
- std::task::Poll::Ready(None) => std::task::Poll::Ready(None),
80
- std::task::Poll::Pending => std::task::Poll::Pending,
81
- }
82
- }
83
- ResponseBody::Incoming(body) => {
84
- let pin = std::pin::Pin::new(body);
85
- match pin.poll_frame(cx) {
86
- std::task::Poll::Ready(Some(Ok(frame))) => {
87
- std::task::Poll::Ready(Some(Ok(frame)))
88
- }
89
- std::task::Poll::Ready(Some(Err(e))) => {
90
- std::task::Poll::Ready(Some(Err(Box::new(e))))
91
- }
92
- std::task::Poll::Ready(None) => std::task::Poll::Ready(None),
93
- std::task::Poll::Pending => std::task::Poll::Pending,
94
- }
95
- }
96
- }
97
- }
98
-
99
- fn is_end_stream(&self) -> bool {
100
- match self {
101
- ResponseBody::Full(body) => body.is_end_stream(),
102
- ResponseBody::Incoming(body) => body.is_end_stream(),
103
- }
104
- }
105
-
106
- fn size_hint(&self) -> http_body::SizeHint {
107
- match self {
108
- ResponseBody::Full(body) => body.size_hint(),
109
- ResponseBody::Incoming(body) => body.size_hint(),
110
- }
111
- }
112
- }
113
-
114
- // Routing types
115
- #[derive(Clone, Debug)]
116
- pub struct RouteTarget {
117
- pub actor_id: Option<Id>,
118
- pub host: String,
119
- pub port: u16,
120
- pub path: String,
121
- }
122
-
123
- #[derive(Clone, Debug)]
124
- pub struct RoutingTimeout {
125
- pub routing_timeout: u64, // in seconds
126
- }
127
-
128
- #[derive(Clone, Debug)]
129
- pub struct RouteConfig {
130
- pub targets: Vec<RouteTarget>,
131
- pub timeout: RoutingTimeout,
132
- }
133
-
134
- #[derive(Clone)]
135
- pub enum RoutingOutput {
136
- /// Return the data to route to.
137
- Route(RouteConfig),
138
- /// Return a custom response.
139
- Response(StructuredResponse),
140
- /// Return a custom serve handler.
141
- CustomServe(Arc<dyn CustomServeTrait>),
142
- }
143
-
144
- #[derive(Clone, Debug)]
145
- pub struct StructuredResponse {
146
- pub status: StatusCode,
147
- pub message: Cow<'static, str>,
148
- pub docs: Option<Cow<'static, str>>,
149
- }
150
-
151
- impl StructuredResponse {
152
- pub fn build_response(&self) -> Result<Response<ResponseBody>> {
153
- let mut body = StdHashMap::new();
154
- body.insert("message", self.message.clone().into_owned());
155
-
156
- if let Some(docs) = &self.docs {
157
- body.insert("docs", docs.clone().into_owned());
158
- }
159
-
160
- let body_json = serde_json::to_string(&body)?;
161
- let bytes = Bytes::from(body_json);
162
-
163
- let response = Response::builder()
164
- .status(self.status)
165
- .header(hyper::header::CONTENT_TYPE, "application/json")
166
- .body(ResponseBody::Full(Full::new(bytes)))?;
167
-
168
- Ok(response)
169
- }
170
- }
171
-
172
- #[derive(Clone)]
173
- enum ResolveRouteOutput {
174
- Target(RouteTarget),
175
- Response(StructuredResponse),
176
- CustomServe(Arc<dyn CustomServeTrait>),
177
- }
178
-
179
- /// Enum defining the type of port the request came in on
180
- #[derive(Clone, Debug, PartialEq)]
181
- pub enum PortType {
182
- Http,
183
- Https,
184
- }
185
-
186
- pub type RoutingFn = Arc<
187
- dyn for<'a> Fn(
188
- &'a str,
189
- &'a str,
190
- PortType,
191
- &'a hyper::HeaderMap,
192
- ) -> futures::future::BoxFuture<'a, Result<RoutingOutput>>
193
- + Send
194
- + Sync,
195
- >;
196
-
197
- pub type CacheKeyFn = Arc<
198
- dyn for<'a> Fn(
199
- &'a str,
200
- &'a str,
201
- &'a hyper::Method,
202
- PortType,
203
- &'a hyper::HeaderMap,
204
- ) -> Result<u64>
205
- + Send
206
- + Sync,
207
- >;
208
-
209
- #[derive(Clone, Debug)]
210
- pub struct MiddlewareConfig {
211
- pub rate_limit: RateLimitConfig,
212
- pub max_in_flight: MaxInFlightConfig,
213
- pub retry: RetryConfig,
214
- pub timeout: TimeoutConfig,
215
- }
216
-
217
- #[derive(Clone, Debug)]
218
- pub struct RateLimitConfig {
219
- pub requests: u64,
220
- pub period: u64, // in seconds
221
- }
222
-
223
- #[derive(Clone, Debug)]
224
- pub struct MaxInFlightConfig {
225
- pub amount: usize,
226
- }
227
-
228
- #[derive(Clone, Debug)]
229
- pub struct RetryConfig {
230
- pub max_attempts: u32,
231
- pub initial_interval: u64, // in milliseconds
232
- }
233
-
234
- #[derive(Clone, Debug)]
235
- pub struct TimeoutConfig {
236
- pub request_timeout: u64, // in seconds
237
- }
238
-
239
- #[derive(Clone, Debug)]
240
- pub enum MiddlewareResponse {
241
- Ok(MiddlewareConfig),
242
- NotFound,
243
- }
244
-
245
- pub type MiddlewareFn = Arc<
246
- dyn for<'a> Fn(
247
- &'a Id,
248
- &'a hyper::HeaderMap,
249
- ) -> futures::future::BoxFuture<'a, Result<MiddlewareResponse>>
250
- + Send
251
- + Sync,
252
- >;
253
-
254
- // Cache for routing results
255
- struct RouteCache {
256
- cache: Cache<u64, RouteConfig>,
257
- }
258
-
259
- impl RouteCache {
260
- fn new() -> Self {
261
- Self {
262
- cache: Cache::builder()
263
- .max_capacity(10_000)
264
- .time_to_live(ROUTE_CACHE_TTL)
265
- .build(),
266
- }
267
- }
268
-
269
- #[tracing::instrument(skip_all)]
270
- async fn get(&self, key: &u64) -> Option<RouteConfig> {
271
- self.cache.get(key).await
272
- }
273
-
274
- #[tracing::instrument(skip_all)]
275
- async fn insert(&self, key: u64, result: RouteConfig) {
276
- self.cache.insert(key, result).await;
277
-
278
- metrics::ROUTE_CACHE_COUNT.record(self.cache.entry_count(), &[]);
279
- }
280
- }
281
-
282
- // Rate limiter
283
- struct RateLimiter {
284
- requests_remaining: u64,
285
- reset_time: Instant,
286
- requests_limit: u64,
287
- period: Duration,
288
- }
289
-
290
- impl RateLimiter {
291
- fn new(requests: u64, period_seconds: u64) -> Self {
292
- Self {
293
- requests_remaining: requests,
294
- reset_time: Instant::now() + Duration::from_secs(period_seconds),
295
- requests_limit: requests,
296
- period: Duration::from_secs(period_seconds),
297
- }
298
- }
299
-
300
- fn try_acquire(&mut self) -> bool {
301
- let now = Instant::now();
302
-
303
- // Check if we need to reset the counter
304
- if now >= self.reset_time {
305
- self.requests_remaining = self.requests_limit;
306
- self.reset_time = now + self.period;
307
- }
308
-
309
- // Try to consume a request
310
- if self.requests_remaining > 0 {
311
- self.requests_remaining -= 1;
312
- true
313
- } else {
314
- false
315
- }
316
- }
317
- }
318
-
319
- // In-flight requests counter
320
- struct InFlightCounter {
321
- count: usize,
322
- max: usize,
323
- }
324
-
325
- impl InFlightCounter {
326
- fn new(max: usize) -> Self {
327
- Self { count: 0, max }
328
- }
329
-
330
- fn try_acquire(&mut self) -> bool {
331
- if self.count < self.max {
332
- self.count += 1;
333
- true
334
- } else {
335
- false
336
- }
337
- }
338
-
339
- fn release(&mut self) {
340
- self.count = self.count.saturating_sub(1);
341
- }
342
- }
343
-
344
47
  // State shared across all request handlers
345
48
  pub struct ProxyState {
346
49
  config: rivet_config::Config,
347
50
  routing_fn: RoutingFn,
348
51
  cache_key_fn: CacheKeyFn,
349
- middleware_fn: MiddlewareFn,
52
+ // NOTE: Using the hyper legacy client is the only option currently.
53
+ // This is what reqwest uses under the hood. Eventually we'll migrate to h3 once it's ready.
54
+ client: Client<
55
+ hyper_tls::HttpsConnector<hyper_util::client::legacy::connect::HttpConnector>,
56
+ Full<Bytes>,
57
+ >,
350
58
  route_cache: RouteCache,
351
- rate_limiters: Cache<(Id, std::net::IpAddr), Arc<Mutex<RateLimiter>>>,
352
- in_flight_counters: Cache<(Id, std::net::IpAddr), Arc<Mutex<InFlightCounter>>>,
353
- in_flight_requests: Arc<Mutex<HashSet<protocol::RequestId>>>,
354
- port_type: PortType,
355
- clickhouse_inserter: Option<clickhouse_inserter::ClickHouseInserterHandle>,
59
+ // We use moka::Cache instead of scc::HashMap because it automatically handles TTL and capacity
60
+ rate_limiters: Cache<std::net::IpAddr, Arc<Mutex<RateLimiter>>>,
61
+ in_flight_counters: Cache<std::net::IpAddr, Arc<Mutex<InFlightCounter>>>,
62
+ in_flight_requests: Cache<protocol::RequestId, ()>,
63
+
356
64
  tasks: Arc<TaskGroup>,
357
65
  }
358
66
 
@@ -361,15 +69,17 @@ impl ProxyState {
361
69
  config: rivet_config::Config,
362
70
  routing_fn: RoutingFn,
363
71
  cache_key_fn: CacheKeyFn,
364
- middleware_fn: MiddlewareFn,
365
- port_type: PortType,
366
- clickhouse_inserter: Option<clickhouse_inserter::ClickHouseInserterHandle>,
367
72
  ) -> Self {
73
+ let https_connector = hyper_tls::HttpsConnector::new();
74
+ let client = Client::builder(TokioExecutor::new())
75
+ .pool_idle_timeout(Duration::from_secs(30))
76
+ .build(https_connector);
77
+
368
78
  Self {
369
79
  config,
370
80
  routing_fn,
371
81
  cache_key_fn,
372
- middleware_fn,
82
+ client,
373
83
  route_cache: RouteCache::new(),
374
84
  rate_limiters: Cache::builder()
375
85
  .max_capacity(10_000)
@@ -379,119 +89,98 @@ impl ProxyState {
379
89
  .max_capacity(10_000)
380
90
  .time_to_live(PROXY_STATE_CACHE_TTL)
381
91
  .build(),
382
- in_flight_requests: Arc::new(Mutex::new(HashSet::new())),
383
- port_type,
384
- clickhouse_inserter,
92
+ in_flight_requests: Cache::builder().max_capacity(10_000_000).build(),
385
93
  tasks: TaskGroup::new(),
386
94
  }
387
95
  }
388
96
 
389
- #[tracing::instrument(skip(self))]
97
+ #[tracing::instrument(skip_all)]
390
98
  async fn resolve_route(
391
99
  &self,
392
- hostname: &str,
393
- path: &str,
394
- method: &hyper::Method,
395
- port_type: PortType,
396
- headers: &hyper::HeaderMap,
100
+ req_ctx: &mut RequestContext,
397
101
  ignore_cache: bool,
398
102
  ) -> Result<ResolveRouteOutput> {
399
- // Extract just the hostname, stripping the port if present
400
- let hostname_only = hostname.split(':').next().unwrap_or(hostname);
401
-
402
103
  tracing::debug!(
403
- hostname = %hostname_only,
404
- path = %path,
405
- method = %method,
406
- port_type = ?port_type,
104
+ hostname = %req_ctx.hostname,
105
+ path = %req_ctx.path,
106
+ method = %req_ctx.method,
407
107
  "Resolving route for request"
408
108
  );
409
109
 
410
- let cache_key =
411
- (self.cache_key_fn)(hostname_only, &path, method, port_type.clone(), headers)?;
110
+ let cache_key = (self.cache_key_fn)(req_ctx)?;
412
111
 
413
112
  // Check cache first
414
- if !ignore_cache {
415
- if let Some(result) = self.route_cache.get(&cache_key).await {
416
- // Choose a random target from the cached targets
417
- if let Some(target) = choose_random_target(&result.targets) {
418
- return Ok(ResolveRouteOutput::Target(target.clone()));
419
- }
420
- }
421
- }
113
+ let cache_res = if !ignore_cache {
114
+ self.route_cache.get(&cache_key).await
115
+ } else {
116
+ None
117
+ };
422
118
 
423
- // Not in cache, call routing function with a default timeout
424
- // Default 15 seconds, routing functions should have their own internal timeouts that are shorter
425
- let default_timeout = Duration::from_secs(15);
119
+ let res = if let Some(res) = cache_res {
120
+ res
121
+ } else {
122
+ // Not in cache, call routing function with a default timeout
123
+ // Default 15 seconds, routing functions should have their own internal timeouts that are shorter
124
+ tracing::debug!(
125
+ hostname = %req_ctx.hostname,
126
+ path = %req_ctx.path,
127
+ cache_hit = false,
128
+ timeout_seconds = DEFAULT_ROUTE_TIMEOUT.as_secs(),
129
+ "Cache miss, calling routing function"
130
+ );
426
131
 
427
- tracing::debug!(
428
- hostname = %hostname_only,
429
- path = %path,
430
- cache_hit = false,
431
- timeout_seconds = default_timeout.as_secs(),
432
- "Cache miss, calling routing function"
433
- );
132
+ let routing_res = timeout(DEFAULT_ROUTE_TIMEOUT, (self.routing_fn)(req_ctx))
133
+ .await
134
+ .map_err(|_| {
135
+ errors::RequestTimeout {
136
+ timeout_seconds: DEFAULT_ROUTE_TIMEOUT.as_secs(),
137
+ }
138
+ .build()
139
+ })??;
434
140
 
435
- let res = timeout(
436
- default_timeout,
437
- (self.routing_fn)(hostname_only, path, port_type, headers),
438
- )
439
- .await
440
- .map_err(|_| {
441
- errors::RequestTimeout {
442
- timeout_seconds: default_timeout.as_secs(),
443
- }
444
- .build()
445
- })?;
141
+ // TODO: Disable route caching for now, determine edge cases with gateway
142
+ // // Cache the result
143
+ // self.route_cache
144
+ // .insert(cache_key, routing_res.clone())
145
+ // .await;
146
+ // tracing::debug!("Added route to cache");
446
147
 
447
- match res? {
148
+ routing_res
149
+ };
150
+
151
+ match res {
448
152
  RoutingOutput::Route(result) => {
449
153
  tracing::debug!(
450
- hostname = %hostname_only,
451
- path = %path,
154
+ hostname = %req_ctx.hostname,
155
+ path = %req_ctx.path,
452
156
  targets_count = result.targets.len(),
453
- timeout_secs = result.timeout.routing_timeout,
454
157
  "Received routing result"
455
158
  );
456
159
 
457
- // Cache the result
458
- self.route_cache.insert(cache_key, result.clone()).await;
459
- tracing::debug!("Added route to cache");
460
-
461
160
  // Choose a random target
462
161
  if let Some(target) = choose_random_target(&result.targets) {
463
162
  tracing::debug!(
464
- hostname = %hostname_only,
465
- path = %path,
163
+ hostname = %req_ctx.hostname,
164
+ path = %req_ctx.path,
466
165
  target_host = %target.host,
467
166
  target_port = target.port,
468
167
  target_path = %target.path,
469
- actor_id = ?target.actor_id,
470
168
  "Selected target for request"
471
169
  );
472
170
  Ok(ResolveRouteOutput::Target(target.clone()))
473
171
  } else {
474
172
  tracing::warn!(
475
- hostname = %hostname_only,
476
- path = %path,
173
+ hostname = %req_ctx.hostname,
174
+ path = %req_ctx.path,
477
175
  "No route targets available from result"
478
176
  );
479
177
  Err(errors::NoRouteTargets.build())
480
178
  }
481
179
  }
482
- RoutingOutput::Response(response) => {
483
- tracing::debug!(
484
- hostname = %hostname_only,
485
- path = %path,
486
- status = ?response.status,
487
- "Routing returned custom response"
488
- );
489
- Ok(ResolveRouteOutput::Response(response))
490
- }
491
180
  RoutingOutput::CustomServe(handler) => {
492
181
  tracing::debug!(
493
- hostname = %hostname_only,
494
- path = %path,
182
+ hostname = %req_ctx.hostname,
183
+ path = %req_ctx.path,
495
184
  "Routing returned custom serve handler"
496
185
  );
497
186
  Ok(ResolveRouteOutput::CustomServe(handler))
@@ -499,183 +188,109 @@ impl ProxyState {
499
188
  }
500
189
  }
501
190
 
191
+ /// Returns true if the rate limit was hit.
502
192
  #[tracing::instrument(skip_all)]
503
- async fn get_middleware_config(
504
- &self,
505
- actor_id: &Id,
506
- headers: &hyper::HeaderMap,
507
- ) -> Result<MiddlewareConfig> {
508
- // Call the middleware function with a timeout
509
- let default_timeout = Duration::from_secs(5); // Default 5 seconds
510
-
511
- let middleware_result =
512
- timeout(default_timeout, (self.middleware_fn)(actor_id, headers)).await;
513
-
514
- match middleware_result {
515
- Ok(result) => match result? {
516
- MiddlewareResponse::Ok(config) => Ok(config),
517
- MiddlewareResponse::NotFound => {
518
- // Default values if middleware not found for this actor
519
- Ok(MiddlewareConfig {
520
- rate_limit: RateLimitConfig {
521
- requests: 100, // 100 requests
522
- period: 60, // per 60 seconds
523
- },
524
- max_in_flight: MaxInFlightConfig {
525
- amount: 20, // 20 concurrent requests
526
- },
527
- retry: RetryConfig {
528
- max_attempts: 3, // 3 retry attempts
529
- initial_interval: 100, // 100ms initial interval
530
- },
531
- timeout: TimeoutConfig {
532
- request_timeout: 30, // 30 seconds for requests
533
- },
534
- })
535
- }
536
- },
537
- Err(_) => {
538
- // Default values if middleware times out
539
- Ok(MiddlewareConfig {
540
- rate_limit: RateLimitConfig {
541
- requests: 100, // 100 requests
542
- period: 60, // per 60 seconds
543
- },
544
- max_in_flight: MaxInFlightConfig {
545
- amount: 20, // 20 concurrent requests
546
- },
547
- retry: RetryConfig {
548
- max_attempts: 3, // 3 retry attempts
549
- initial_interval: 100, // 100ms initial interval
550
- },
551
- timeout: TimeoutConfig {
552
- request_timeout: 30, // 30 seconds for requests
553
- },
554
- })
555
- }
556
- }
557
- }
558
-
559
- #[tracing::instrument(skip_all)]
560
- async fn check_rate_limit(
561
- &self,
562
- ip_addr: std::net::IpAddr,
563
- actor_id: &Option<Id>,
564
- headers: &hyper::HeaderMap,
565
- ) -> Result<bool> {
566
- let Some(actor_id) = *actor_id else {
567
- // No rate limiting when actor_id is None
568
- return Ok(true);
569
- };
570
-
571
- // Get actor-specific middleware config
572
- let middleware_config = self.get_middleware_config(&actor_id, headers).await?;
573
-
574
- let cache_key = (actor_id, ip_addr);
575
-
193
+ async fn check_rate_limit(&self, req_ctx: &RequestContext) -> Result<bool> {
576
194
  // Get existing limiter or create a new one
577
- let limiter_arc = if let Some(existing_limiter) = self.rate_limiters.get(&cache_key).await {
578
- existing_limiter
579
- } else {
580
- let new_limiter = Arc::new(Mutex::new(RateLimiter::new(
581
- middleware_config.rate_limit.requests,
582
- middleware_config.rate_limit.period,
583
- )));
584
- self.rate_limiters
585
- .insert(cache_key, new_limiter.clone())
586
- .await;
587
- metrics::RATE_LIMITER_COUNT.record(self.rate_limiters.entry_count(), &[]);
588
- new_limiter
589
- };
195
+ let limiter_arc =
196
+ if let Some(existing_limiter) = self.rate_limiters.get(&req_ctx.client_ip).await {
197
+ existing_limiter
198
+ } else {
199
+ let new_limiter = Arc::new(Mutex::new(RateLimiter::new(
200
+ req_ctx.rate_limit.requests,
201
+ req_ctx.rate_limit.period,
202
+ )));
203
+ self.rate_limiters
204
+ .insert(req_ctx.client_ip, new_limiter.clone())
205
+ .await;
206
+ metrics::RATE_LIMITER_COUNT.set(self.rate_limiters.entry_count() as i64);
207
+ new_limiter
208
+ };
590
209
 
591
210
  // Try to acquire from the limiter
592
- let result = {
211
+ let acquired = {
593
212
  let mut limiter = limiter_arc.lock().await;
594
213
  limiter.try_acquire()
595
214
  };
596
215
 
597
- Ok(result)
216
+ Ok(!acquired)
598
217
  }
599
218
 
219
+ /// Returns true if the counter could not be acquired.
600
220
  #[tracing::instrument(skip_all)]
601
- async fn acquire_in_flight(
602
- &self,
603
- ip_addr: std::net::IpAddr,
604
- actor_id: &Option<Id>,
605
- headers: &hyper::HeaderMap,
606
- ) -> Result<Option<protocol::RequestId>> {
607
- // Check in-flight limit if actor_id is present
608
- if let Some(actor_id) = *actor_id {
609
- // Get actor-specific middleware config
610
- let middleware_config = self.get_middleware_config(&actor_id, headers).await?;
611
-
612
- let cache_key = (actor_id, ip_addr);
613
-
614
- // Get existing counter or create a new one
615
- let counter_arc = if let Some(existing_counter) =
616
- self.in_flight_counters.get(&cache_key).await
617
- {
221
+ async fn acquire_in_flight(&self, req_ctx: &mut RequestContext) -> Result<bool> {
222
+ let cache_key = req_ctx.client_ip;
223
+
224
+ // Get existing counter or create a new one
225
+ let counter_arc =
226
+ if let Some(existing_counter) = self.in_flight_counters.get(&cache_key).await {
618
227
  existing_counter
619
228
  } else {
620
229
  let new_counter = Arc::new(Mutex::new(InFlightCounter::new(
621
- middleware_config.max_in_flight.amount,
230
+ req_ctx.max_in_flight.amount,
622
231
  )));
623
232
  self.in_flight_counters
624
233
  .insert(cache_key, new_counter.clone())
625
234
  .await;
626
- metrics::IN_FLIGHT_COUNTER_COUNT.record(self.in_flight_counters.entry_count(), &[]);
235
+ metrics::IN_FLIGHT_COUNTER_COUNT.set(self.in_flight_counters.entry_count() as i64);
627
236
  new_counter
628
237
  };
629
238
 
630
- // Try to acquire from the counter
631
- let acquired = {
632
- let mut counter = counter_arc.lock().await;
633
- counter.try_acquire()
634
- };
239
+ // Try to acquire from the counter
240
+ let acquired = {
241
+ let mut counter = counter_arc.lock().await;
242
+ counter.try_acquire()
243
+ };
635
244
 
636
- if !acquired {
637
- return Ok(None); // Rate limited
638
- }
245
+ if !acquired {
246
+ return Ok(true); // Rate limited
639
247
  }
640
248
 
641
249
  // Generate unique request ID
642
- let request_id = Some(self.generate_unique_request_id().await?);
643
- Ok(request_id)
250
+ req_ctx.in_flight_request_id = Some(self.generate_unique_in_flight_request_id().await?);
251
+
252
+ Ok(false)
644
253
  }
645
254
 
646
255
  #[tracing::instrument(skip_all)]
647
256
  async fn release_in_flight(
648
257
  &self,
649
- ip_addr: std::net::IpAddr,
650
- actor_id: &Option<Id>,
651
- request_id: protocol::RequestId,
258
+ client_ip: IpAddr,
259
+ in_flight_request_id: Option<protocol::RequestId>,
652
260
  ) {
653
- // Release in-flight counter if actor_id is present
654
- if let Some(actor_id) = *actor_id {
655
- let cache_key = (actor_id, ip_addr);
656
- if let Some(counter_arc) = self.in_flight_counters.get(&cache_key).await {
657
- let mut counter = counter_arc.lock().await;
658
- counter.release();
659
- }
261
+ if let Some(counter_arc) = self.in_flight_counters.get(&client_ip).await {
262
+ let mut counter = counter_arc.lock().await;
263
+ counter.release();
660
264
  }
661
265
 
662
- // Release request ID
663
- let mut requests = self.in_flight_requests.lock().await;
664
- requests.remove(&request_id);
266
+ if let Some(in_flight_request_id) = in_flight_request_id {
267
+ // Release request ID
268
+ self.in_flight_requests
269
+ .invalidate(&in_flight_request_id)
270
+ .await;
271
+ metrics::IN_FLIGHT_REQUEST_COUNT.set(self.in_flight_requests.entry_count() as i64);
272
+ }
665
273
  }
666
274
 
667
275
  /// Generate a unique request ID that is not currently in flight
668
- async fn generate_unique_request_id(&self) -> Result<protocol::RequestId> {
276
+ async fn generate_unique_in_flight_request_id(&self) -> Result<protocol::RequestId> {
669
277
  const MAX_TRIES: u32 = 100;
670
- let mut requests = self.in_flight_requests.lock().await;
671
278
 
672
279
  for attempt in 0..MAX_TRIES {
673
280
  let request_id = protocol::util::generate_request_id();
281
+ let mut inserted = false;
674
282
 
675
283
  // Check if this ID is already in use
676
- if !requests.contains(&request_id) {
677
- // Insert the ID and return it
678
- requests.insert(request_id);
284
+ self.in_flight_requests
285
+ .entry(request_id)
286
+ .or_insert_with(async {
287
+ inserted = true;
288
+ })
289
+ .await;
290
+
291
+ if inserted {
292
+ metrics::IN_FLIGHT_REQUEST_COUNT.set(self.in_flight_requests.entry_count() as i64);
293
+
679
294
  return Ok(request_id);
680
295
  }
681
296
 
@@ -697,91 +312,66 @@ impl ProxyState {
697
312
 
698
313
  // Helper function to choose a random target from a list of targets
699
314
  fn choose_random_target(targets: &[RouteTarget]) -> Option<&RouteTarget> {
700
- if targets.is_empty() {
701
- return None;
702
- }
703
-
704
- // Use a simple random index selection
705
- let random_index = rand::random::<usize>() % targets.len();
706
- targets.get(random_index)
315
+ targets.choose(&mut rand::thread_rng())
707
316
  }
708
317
 
709
318
  // Proxy service
710
319
  pub struct ProxyService {
711
320
  state: Arc<ProxyState>,
712
321
  remote_addr: SocketAddr,
713
- // Note: Using the hyper legacy client is the only option currently.
714
- // This is what reqwest uses under the hood. Eventually we'll migrate to h3 once it's ready.
715
- client: Client<hyper_util::client::legacy::connect::HttpConnector, Full<Bytes>>,
322
+ connection_start: Instant,
716
323
  }
717
324
 
718
325
  impl ProxyService {
719
326
  pub fn new(state: Arc<ProxyState>, remote_addr: SocketAddr) -> Self {
720
- // Create a client with the hyper-util legacy client
721
- let client = Client::builder(TokioExecutor::new())
722
- .pool_idle_timeout(Duration::from_secs(30))
723
- .build_http();
724
-
725
327
  Self {
726
328
  state,
727
329
  remote_addr,
728
- client,
330
+ connection_start: Instant::now(),
729
331
  }
730
332
  }
731
333
 
732
- // Calculate backoff duration for a given retry attempt
733
- pub fn calculate_backoff(attempt: u32, initial_interval: u64) -> Duration {
734
- Duration::from_millis(initial_interval * 2u64.pow(attempt - 1))
735
- }
334
+ /// Process an individual request.
335
+ #[tracing::instrument(name = "guard_request", skip_all, fields(ray_id, req_id, uri=%req.uri()))]
336
+ pub async fn process(&self, mut req: Request<BodyIncoming>) -> Result<Response<ResponseBody>> {
337
+ let start_time = Instant::now();
736
338
 
737
- #[tracing::instrument(skip_all)]
738
- async fn handle_request(
739
- &self,
740
- req: Request<BodyIncoming>,
741
- start_time: Instant,
742
- request_context: &mut RequestContext,
743
- ) -> Result<Response<ResponseBody>> {
339
+ let request_ids = RequestIds::new(self.state.config.dc_label());
340
+ req.extensions_mut().insert(request_ids);
341
+
342
+ let current_span = tracing::Span::current();
343
+
344
+ current_span.record("req_id", request_ids.req_id.to_string());
345
+ current_span.record("ray_id", request_ids.ray_id.to_string());
346
+
347
+ // Extract request information for logging and analytics before consuming the request
348
+ let incoming_ray_id = req
349
+ .headers()
350
+ .get(X_RIVET_RAY_ID)
351
+ .and_then(|h| h.to_str().ok())
352
+ .and_then(|id| Id::parse(id).ok());
744
353
  let host = req
745
354
  .headers()
746
355
  .get(hyper::header::HOST)
747
356
  .and_then(|h| h.to_str().ok())
748
- .unwrap_or("unknown");
749
-
357
+ .unwrap_or("unknown")
358
+ .to_string();
359
+ let uri_string = req.uri().to_string();
750
360
  let path = req
751
361
  .uri()
752
362
  .path_and_query()
753
363
  .map(|x| x.to_string())
754
364
  .unwrap_or_else(|| req.uri().path().to_string());
365
+ let method = req.method().clone();
755
366
 
756
- // Set request body size in analytics (will be updated with actual size later)
757
-
758
- let target_res = self
759
- .state
760
- .resolve_route(
761
- host,
762
- &path,
763
- req.method(),
764
- self.state.port_type.clone(),
765
- req.headers(),
766
- false,
767
- )
768
- .await;
769
-
770
- let duration_secs = start_time.elapsed().as_secs_f64();
771
- metrics::RESOLVE_ROUTE_DURATION.record(duration_secs, &[]);
772
-
773
- // Resolve target
774
- let target = target_res?;
775
- if let ResolveRouteOutput::Response(response) = &target {
776
- // Return the custom response
777
- return response.build_response();
778
- }
367
+ current_span.set_attribute("http.request.method", method.to_string());
368
+ current_span.set_attribute("http.path", uri_string.clone());
779
369
 
780
- let actor_id = if let ResolveRouteOutput::Target(target) = &target {
781
- target.actor_id
782
- } else {
783
- None
784
- };
370
+ let user_agent = req
371
+ .headers()
372
+ .get(hyper::header::USER_AGENT)
373
+ .and_then(|h| h.to_str().ok())
374
+ .map(|s| s.to_string());
785
375
 
786
376
  // Extract IP address from X-Forwarded-For header or fall back to remote_addr
787
377
  let client_ip = req
@@ -795,74 +385,327 @@ impl ProxyService {
795
385
  .and_then(|ip_str| ip_str.parse::<std::net::IpAddr>().ok())
796
386
  .unwrap_or_else(|| self.remote_addr.ip());
797
387
 
798
- // Apply rate limiting
799
- if !self
800
- .state
801
- .check_rate_limit(client_ip, &actor_id, req.headers())
802
- .await?
803
- {
804
- return Err(errors::RateLimit {
805
- actor_id,
806
- method: req.method().to_string(),
807
- path: path.clone(),
808
- ip: client_ip.to_string(),
809
- }
810
- .build());
811
- }
388
+ let is_websocket = hyper_tungstenite::is_upgrade_request(&req);
389
+ let mut req_ctx = RequestContext::new(
390
+ self.remote_addr,
391
+ request_ids.ray_id,
392
+ request_ids.req_id,
393
+ host,
394
+ path,
395
+ req.method().clone(),
396
+ req.headers().clone(),
397
+ is_websocket,
398
+ client_ip,
399
+ start_time,
400
+ );
812
401
 
813
- // Acquire in-flight limit and generate request ID
814
- let request_id = match self
815
- .state
816
- .acquire_in_flight(client_ip, &actor_id, req.headers())
817
- .await?
818
- {
819
- Some(id) => id,
820
- None => {
821
- return Err(errors::RateLimit {
822
- actor_id,
823
- method: req.method().to_string(),
824
- path: path.clone(),
825
- ip: client_ip.to_string(),
826
- }
827
- .build());
828
- }
829
- };
402
+ // TLS information would be set here if available (for HTTPS connections)
403
+ // This requires TLS connection introspection and is marked for future enhancement
830
404
 
831
- // Increment metrics
832
- metrics::PROXY_REQUEST_PENDING.add(1, &[]);
833
- metrics::PROXY_REQUEST_TOTAL.add(1, &[]);
405
+ // Debug log request information with structured fields (Apache-like access log)
406
+ tracing::debug!(
407
+ ?incoming_ray_id,
408
+ ray_id=?req_ctx.ray_id,
409
+ req_id=?req_ctx.req_id,
410
+ method=%req_ctx.method,
411
+ path=%req_ctx.path,
412
+ host=%req_ctx.host,
413
+ remote_addr=%req_ctx.remote_addr,
414
+ uri=%uri_string,
415
+ user_agent=?user_agent,
416
+ "Request received"
417
+ );
834
418
 
835
- // Update request context with target info
836
- if let Some(actor_id) = actor_id {
837
- request_context.service_actor_id = Some(actor_id);
419
+ // Used for ws error proxying later
420
+ let mut mock_req_builder = Request::builder()
421
+ .method(req.method().clone())
422
+ .uri(req.uri().clone())
423
+ .version(req.version().clone());
424
+ if let Some(headers) = mock_req_builder.headers_mut() {
425
+ *headers = req.headers().clone();
838
426
  }
427
+ if let Some(extensions) = mock_req_builder.extensions_mut() {
428
+ *extensions = req.extensions().clone();
429
+ }
430
+ let mock_req = mock_req_builder.body(())?;
839
431
 
840
- let res = if hyper_tungstenite::is_upgrade_request(&req) {
841
- self.handle_websocket_upgrade(req, target, request_context, client_ip, actor_id)
842
- .await
843
- } else {
844
- self.handle_http_request(req, target, request_context, client_ip, actor_id)
845
- .await
846
- };
847
-
848
- let status = match &res {
849
- Ok(resp) => resp.status().as_u16().to_string(),
850
- Err(_) => "error".to_string(),
851
- };
852
-
853
- // Record metrics
854
- let duration_secs = start_time.elapsed().as_secs_f64();
855
- metrics::PROXY_REQUEST_DURATION
856
- .record(duration_secs, &[KeyValue::new("status", status.clone())]);
432
+ // Process the request
433
+ let mut res = match self.handle_request(req, &mut req_ctx).await {
434
+ Ok(res) => res,
435
+ Err(err) => {
436
+ // Log the error
437
+ tracing::error!(?err, "Request failed");
857
438
 
858
- metrics::PROXY_REQUEST_PENDING.add(-1, &[]);
439
+ metrics::PROXY_REQUEST_ERROR_TOTAL
440
+ .with_label_values(&[&err.to_string()])
441
+ .inc();
859
442
 
860
- // Release in-flight counter and request ID when done
861
- let state_clone = self.state.clone();
862
- tokio::spawn(
443
+ // If we receive an error during a websocket request, we attempt to open the websocket anyway
444
+ // so we can send the error via websocket instead of http. Most websocket clients don't handle
445
+ // HTTP errors in a meaningful way resulting in unhelpful errors for the user
446
+ if is_websocket {
447
+ tracing::debug!("Upgrading client connection to WebSocket for error proxy");
448
+ match hyper_tungstenite::upgrade(mock_req, None) {
449
+ Ok((client_response, client_ws)) => {
450
+ tracing::debug!("Client WebSocket upgrade for error proxy successful");
451
+
452
+ self.state.tasks.spawn(
453
+ async move {
454
+ let ws_handle = match WebSocketHandle::new(client_ws).await {
455
+ Ok(ws_handle) => ws_handle,
456
+ Err(err) => {
457
+ tracing::debug!(
458
+ ?err,
459
+ "failed initiating websocket handle for error proxy"
460
+ );
461
+ return;
462
+ }
463
+ };
464
+ let frame = utils::err_to_close_frame(err, request_ids.ray_id);
465
+
466
+ // Manual conversion to handle different tungstenite versions
467
+ let code_num: u16 = frame.code.into();
468
+ let reason = frame.reason.clone();
469
+
470
+ if let Err(err) = ws_handle
471
+ .send(tokio_tungstenite::tungstenite::Message::Close(Some(
472
+ tokio_tungstenite::tungstenite::protocol::CloseFrame {
473
+ code: code_num.into(),
474
+ reason,
475
+ },
476
+ )))
477
+ .await
478
+ {
479
+ tracing::debug!(
480
+ ?err,
481
+ "failed sending websocket error proxy"
482
+ );
483
+ }
484
+
485
+ // Flush to ensure close frame is sent
486
+ if let Err(err) = ws_handle.flush().await {
487
+ tracing::debug!(
488
+ ?err,
489
+ "failed flushing websocket in error proxy"
490
+ );
491
+ }
492
+
493
+ // Keep TCP connection open briefly to allow client to process close
494
+ tokio::time::sleep(WEBSOCKET_CLOSE_LINGER).await;
495
+ }
496
+ .instrument(tracing::info_span!("ws_error_proxy_task")),
497
+ );
498
+
499
+ // Return the response that will upgrade the client connection
500
+ // For proper WebSocket handshaking, we need to preserve the original response
501
+ // structure but convert it to our expected return type without modifying its content
502
+ tracing::debug!(
503
+ "Returning WebSocket upgrade response for error proxy to client"
504
+ );
505
+ // Extract the parts from the response but preserve all headers and status
506
+ let (mut parts, _) = client_response.into_parts();
507
+
508
+ // Add Sec-WebSocket-Protocol header to the response
509
+ // Many WebSocket clients (e.g. node-ws & Cloudflare) require a protocol in the response
510
+ parts.headers.insert(
511
+ "sec-websocket-protocol",
512
+ hyper::header::HeaderValue::from_static("rivet"),
513
+ );
514
+
515
+ // Create a new response with an empty body - WebSocket upgrades don't need a body
516
+ Response::from_parts(
517
+ parts,
518
+ ResponseBody::Full(Full::<Bytes>::new(Bytes::new())),
519
+ )
520
+ }
521
+ Err(err) => {
522
+ tracing::error!(
523
+ ?err,
524
+ "Failed to upgrade client WebSocket for error proxy"
525
+ );
526
+
527
+ utils::err_into_response(
528
+ errors::ConnectionError {
529
+ error_message: format!(
530
+ "Failed to upgrade client WebSocket for error proxy: {}",
531
+ err
532
+ ),
533
+ remote_addr: req_ctx.remote_addr.to_string(),
534
+ }
535
+ .build(),
536
+ )?
537
+ }
538
+ }
539
+ } else {
540
+ utils::err_into_response(err)?
541
+ }
542
+ }
543
+ };
544
+
545
+ if is_websocket && res.status() != StatusCode::SWITCHING_PROTOCOLS {
546
+ tracing::debug!("returned non-101 response to websocket");
547
+ }
548
+
549
+ // Add ray_id to response headers
550
+ if let Ok(ray_id_value) = request_ids.ray_id.to_string().parse() {
551
+ if let Some(existing_ray_id_value) = res
552
+ .headers()
553
+ .get(X_RIVET_RAY_ID)
554
+ .and_then(|h| h.to_str().ok())
555
+ {
556
+ if ray_id_value != existing_ray_id_value {
557
+ tracing::warn!(
558
+ expected_ray_id=%request_ids.ray_id,
559
+ received_ray_id=%existing_ray_id_value,
560
+ "downstream service set ray id header to a different value",
561
+ );
562
+ }
563
+ }
564
+
565
+ res.headers_mut().insert(X_RIVET_RAY_ID, ray_id_value);
566
+ }
567
+
568
+ // Add cors headers to response
569
+ if let Some(cors) = &req_ctx.cors {
570
+ let headers = res.headers_mut();
571
+
572
+ headers.insert(
573
+ "access-control-allow-origin",
574
+ HeaderValue::from_str(&cors.allow_origin)?,
575
+ );
576
+ headers.insert(
577
+ "access-control-allow-credentials",
578
+ HeaderValue::from_static(if cors.allow_credentials {
579
+ "true"
580
+ } else {
581
+ "false"
582
+ }),
583
+ );
584
+ headers.insert(
585
+ "access-control-expose-headers",
586
+ HeaderValue::from_str(&cors.expose_headers)?,
587
+ );
588
+
589
+ if let Some(allow_methods) = &cors.allow_methods {
590
+ headers.insert(
591
+ "access-control-allow-methods",
592
+ HeaderValue::from_str(allow_methods)?,
593
+ );
594
+ }
595
+
596
+ if let Some(allow_headers) = &cors.allow_headers {
597
+ headers.insert(
598
+ "access-control-allow-headers",
599
+ HeaderValue::from_str(allow_headers)?,
600
+ );
601
+ }
602
+
603
+ if let Some(max_age) = &cors.max_age {
604
+ headers.insert(
605
+ "access-control-max-age",
606
+ HeaderValue::from_str(&max_age.to_string())?,
607
+ );
608
+ }
609
+
610
+ // Add Vary header to prevent cache poisoning when echoing origin
611
+ if cors.allow_origin != "*" {
612
+ headers.insert("vary", HeaderValue::from_static("Origin"));
613
+ }
614
+ }
615
+
616
+ // Set span status code
617
+ let status = res.status().as_u16();
618
+ current_span.set_attribute("http.response.status_code", status as i64);
619
+
620
+ let content_length = res
621
+ .headers()
622
+ .get(hyper::header::CONTENT_LENGTH)
623
+ .and_then(|h| h.to_str().ok())
624
+ .and_then(|s| s.parse::<usize>().ok())
625
+ .unwrap_or(0);
626
+
627
+ // Log information about the completed request
628
+ tracing::debug!(
629
+ ?incoming_ray_id,
630
+ ray_id=?req_ctx.ray_id,
631
+ req_id=?req_ctx.req_id,
632
+ method = %req_ctx.method,
633
+ path = %req_ctx.path,
634
+ host = %req_ctx.host,
635
+ remote_addr = %req_ctx.remote_addr,
636
+ status = %status,
637
+ content_length = %content_length,
638
+ "Request completed"
639
+ );
640
+
641
+ Ok(res)
642
+ }
643
+
644
+ #[tracing::instrument(skip_all)]
645
+ async fn handle_request(
646
+ &self,
647
+ req: Request<BodyIncoming>,
648
+ req_ctx: &mut RequestContext,
649
+ ) -> Result<Response<ResponseBody>> {
650
+ // Resolve target
651
+ let target_res = self.state.resolve_route(req_ctx, false).await;
652
+
653
+ let duration_secs = req_ctx.start_time.elapsed().as_secs_f64();
654
+ metrics::RESOLVE_ROUTE_DURATION.observe(duration_secs);
655
+
656
+ let target = target_res?;
657
+
658
+ // Apply rate limiting
659
+ if self.state.check_rate_limit(req_ctx).await? {
660
+ return Err(errors::RateLimit {
661
+ method: req_ctx.method.to_string(),
662
+ path: req_ctx.path.clone(),
663
+ ip: req_ctx.client_ip.to_string(),
664
+ }
665
+ .build());
666
+ }
667
+
668
+ // Acquire in-flight limit and generate protocol request ID
669
+ if self.state.acquire_in_flight(req_ctx).await? {
670
+ return Err(errors::RateLimit {
671
+ method: req_ctx.method.to_string(),
672
+ path: req_ctx.path.clone(),
673
+ ip: req_ctx.client_ip.to_string(),
674
+ }
675
+ .build());
676
+ }
677
+
678
+ // Increment metrics
679
+ metrics::PROXY_REQUEST_PENDING.inc();
680
+ metrics::PROXY_REQUEST_TOTAL.inc();
681
+
682
+ let res = if hyper_tungstenite::is_upgrade_request(&req) {
683
+ self.handle_websocket_upgrade(req, req_ctx, target).await
684
+ } else {
685
+ self.handle_http_request(req, req_ctx, target).await
686
+ };
687
+
688
+ let status = match &res {
689
+ Ok(resp) => resp.status().as_u16().to_string(),
690
+ Err(_) => "error".to_string(),
691
+ };
692
+
693
+ // Record metrics
694
+ let duration_secs = req_ctx.start_time.elapsed().as_secs_f64();
695
+ metrics::PROXY_REQUEST_DURATION
696
+ .with_label_values(&[status])
697
+ .observe(duration_secs);
698
+
699
+ metrics::PROXY_REQUEST_PENDING.dec();
700
+
701
+ // Release in-flight counter and request ID when done
702
+ let state_clone = self.state.clone();
703
+ let client_ip = req_ctx.client_ip;
704
+ let in_flight_request_id = req_ctx.in_flight_request_id;
705
+ tokio::spawn(
863
706
  async move {
864
707
  state_clone
865
- .release_in_flight(client_ip, &actor_id, request_id)
708
+ .release_in_flight(client_ip, in_flight_request_id)
866
709
  .await;
867
710
  }
868
711
  .instrument(tracing::info_span!("release_in_flight_task")),
@@ -875,95 +718,40 @@ impl ProxyService {
875
718
  async fn handle_http_request(
876
719
  &self,
877
720
  req: Request<BodyIncoming>,
721
+ req_ctx: &mut RequestContext,
878
722
  resolved_route: ResolveRouteOutput,
879
- request_context: &mut RequestContext,
880
- client_ip: std::net::IpAddr,
881
- actor_id: Option<Id>,
882
723
  ) -> Result<Response<ResponseBody>> {
883
- // Get middleware config for this actor if it exists
884
- let middleware_config = if let ResolveRouteOutput::Target(target) = &resolved_route
885
- && let Some(actor_id) = &target.actor_id
886
- {
887
- self.state
888
- .get_middleware_config(actor_id, req.headers())
889
- .await?
890
- } else {
891
- // Default middleware config for targets without actor_id
892
- MiddlewareConfig {
893
- rate_limit: RateLimitConfig {
894
- requests: 100, // 100 requests
895
- period: 60, // per 60 seconds
896
- },
897
- max_in_flight: MaxInFlightConfig {
898
- amount: 20, // 20 concurrent requests
899
- },
900
- retry: RetryConfig {
901
- max_attempts: 3, // 3 retry attempts
902
- initial_interval: 100, // 100ms initial interval
903
- },
904
- timeout: TimeoutConfig {
905
- request_timeout: 30, // 30 seconds for requests
906
- },
907
- }
908
- };
909
-
910
- let host = req
911
- .headers()
912
- .get(hyper::header::HOST)
913
- .and_then(|h| h.to_str().ok())
914
- .unwrap_or("unknown")
915
- .to_string();
916
-
917
- let path = req
918
- .uri()
919
- .path_and_query()
920
- .map(|x| x.to_string())
921
- .unwrap_or_else(|| req.uri().path().to_string());
922
-
923
- // Set up retry with backoff from middleware config
924
- let max_attempts = middleware_config.retry.max_attempts;
925
- let initial_interval = middleware_config.retry.initial_interval;
926
- let timeout_duration = Duration::from_secs(middleware_config.timeout.request_timeout);
724
+ // Set up retry with backoff
725
+ let timeout_duration = Duration::from_secs(req_ctx.timeout.request_timeout);
927
726
 
928
727
  match resolved_route {
929
728
  ResolveRouteOutput::Target(mut target) => {
930
- // Set service IP from target
931
- if let Ok(target_ip) =
932
- format!("{}:{}", target.host, target.port).parse::<std::net::SocketAddr>()
933
- {
934
- request_context.service_ip = Some(target_ip.ip());
935
- }
936
-
937
729
  // Read the request body before proceeding with retries
938
730
  let (req_parts, body) = req.into_parts();
939
- let req_body = match http_body_util::BodyExt::collect(body).await {
940
- Ok(collected) => collected.to_bytes(),
941
- Err(err) => {
942
- tracing::debug!(?err, "Failed to read request body");
943
- Bytes::new()
944
- }
945
- };
946
-
947
- // Set actual request body size in analytics
948
- request_context.client_request_body_bytes = Some(req_body.len() as u64);
731
+ let req_body =
732
+ Limited::new(body, self.state.config.guard().http_max_request_body_size())
733
+ .collect()
734
+ .await
735
+ .map_err(|err| errors::InvalidRequestBody(err.to_string()).build())?
736
+ .to_bytes();
949
737
 
950
738
  // Use a value-returning loop to handle both errors and successful responses
951
739
  let mut attempts = 0;
952
- while attempts < max_attempts {
740
+ while attempts < req_ctx.retry.max_attempts {
953
741
  attempts += 1;
954
742
 
955
743
  // Use the common function to build request parts
956
- let builder = self
957
- .proxied_request_builder(&req_parts, &target)
744
+ let builder = utils::proxied_request_builder(&req_parts, req_ctx, &target)
958
745
  .map_err(|err| errors::HttpRequestBuildFailed(err.to_string()).build())?;
959
746
 
960
747
  // Create the final request with body
961
748
  let proxied_req = builder
962
- .body(Full::<Bytes>::new(req_body.clone()))
749
+ // NOTE: the `Bytes` type is cheaply cloneable, this is not resource intensive
750
+ .body(Full::new(req_body.clone()))
963
751
  .map_err(|err| errors::RequestBuildError(err.to_string()).build())?;
964
752
 
965
753
  // Send the request with timeout
966
- let res = timeout(timeout_duration, self.client.request(proxied_req))
754
+ let res = timeout(timeout_duration, self.state.client.request(proxied_req))
967
755
  .await
968
756
  .map_err(|_| {
969
757
  errors::RequestTimeout {
@@ -975,29 +763,23 @@ impl ProxyService {
975
763
  match res {
976
764
  Ok(resp) => {
977
765
  // Check if this is a retryable response
978
- if should_retry_request_inner(resp.status(), resp.headers()) {
766
+ if utils::should_retry_request_inner(resp.status(), resp.headers()) {
979
767
  // Request connect error, might retry
980
768
  tracing::debug!(
981
769
  "Request attempt {attempts} failed (service unavailable)"
982
770
  );
983
771
 
984
772
  // Use backoff and continue
985
- let backoff = Self::calculate_backoff(attempts, initial_interval);
773
+ let backoff = utils::calculate_backoff(
774
+ attempts,
775
+ req_ctx.retry.initial_interval,
776
+ );
986
777
  tokio::time::sleep(backoff).await;
987
778
 
988
779
  // Resolve target again, this time ignoring cache. This makes sure
989
780
  // we always re-fetch the route on error
990
- let ResolveRouteOutput::Target(new_target) = self
991
- .state
992
- .resolve_route(
993
- &host,
994
- &path,
995
- &req_parts.method,
996
- self.state.port_type.clone(),
997
- &req_parts.headers,
998
- true,
999
- )
1000
- .await?
781
+ let ResolveRouteOutput::Target(new_target) =
782
+ self.state.resolve_route(req_ctx, true).await?
1001
783
  else {
1002
784
  bail!("resolved route does not match Target");
1003
785
  };
@@ -1019,28 +801,27 @@ impl ProxyService {
1019
801
  // For streaming responses, pass through the body without buffering
1020
802
  tracing::debug!("Detected streaming response, preserving stream");
1021
803
 
1022
- // We can't easily calculate response size for streaming, so set it to None
1023
- request_context.guard_response_body_bytes = None;
1024
-
1025
804
  let streaming_body = ResponseBody::Incoming(body);
1026
805
  return Ok(Response::from_parts(parts, streaming_body));
1027
806
  } else {
1028
807
  // For non-streaming responses, buffer as before
1029
- let body_bytes = match BodyExt::collect(body).await {
1030
- Ok(collected) => collected.to_bytes(),
1031
- Err(_) => Bytes::new(),
1032
- };
1033
-
1034
- // Set actual response body size in analytics
1035
- request_context.guard_response_body_bytes =
1036
- Some(body_bytes.len() as u64);
808
+ let body_bytes = Limited::new(
809
+ body,
810
+ self.state.config.guard().http_max_request_body_size(),
811
+ )
812
+ .collect()
813
+ .await
814
+ .map_err(|err| {
815
+ errors::InvalidResponseBody(err.to_string()).build()
816
+ })?
817
+ .to_bytes();
1037
818
 
1038
819
  let full_body = ResponseBody::Full(Full::new(body_bytes));
1039
820
  return Ok(Response::from_parts(parts, full_body));
1040
821
  }
1041
822
  }
1042
823
  Err(err) => {
1043
- if !err.is_connect() || attempts >= max_attempts {
824
+ if !err.is_connect() || attempts >= req_ctx.retry.max_attempts {
1044
825
  tracing::error!(
1045
826
  ?err,
1046
827
  ?target,
@@ -1057,22 +838,16 @@ impl ProxyService {
1057
838
  tracing::debug!(?err, "Request attempt {attempts} failed");
1058
839
 
1059
840
  // Use backoff and continue
1060
- let backoff = Self::calculate_backoff(attempts, initial_interval);
841
+ let backoff = utils::calculate_backoff(
842
+ attempts,
843
+ req_ctx.retry.initial_interval,
844
+ );
1061
845
  tokio::time::sleep(backoff).await;
1062
846
 
1063
847
  // Resolve target again, this time ignoring cache. This makes sure
1064
848
  // we always re-fetch the route on error
1065
- let ResolveRouteOutput::Target(new_target) = self
1066
- .state
1067
- .resolve_route(
1068
- &host,
1069
- &path,
1070
- &req_parts.method,
1071
- self.state.port_type.clone(),
1072
- &req_parts.headers,
1073
- true,
1074
- )
1075
- .await?
849
+ let ResolveRouteOutput::Target(new_target) =
850
+ self.state.resolve_route(req_ctx, true).await?
1076
851
  else {
1077
852
  bail!("resolved route does not match Target");
1078
853
  };
@@ -1086,77 +861,40 @@ impl ProxyService {
1086
861
 
1087
862
  // If we get here, all attempts failed
1088
863
  return Err(errors::RetryAttemptsExceeded {
1089
- attempts: max_attempts,
864
+ attempts: req_ctx.retry.max_attempts,
1090
865
  }
1091
866
  .build());
1092
867
  }
1093
- ResolveRouteOutput::Response(_) => {
1094
- unreachable!()
1095
- }
1096
868
  ResolveRouteOutput::CustomServe(mut handler) => {
1097
- let req_headers = req.headers().clone();
1098
- let req_method = req.method().clone();
1099
-
1100
- // Acquire in-flight limit and generate request ID
1101
- let request_id = match self
1102
- .state
1103
- .acquire_in_flight(client_ip, &actor_id, &req_headers)
1104
- .await?
1105
- {
1106
- Some(id) => id,
1107
- None => {
1108
- return Err(errors::RateLimit {
1109
- actor_id,
1110
- method: req_method.to_string(),
1111
- path: path.clone(),
1112
- ip: client_ip.to_string(),
1113
- }
1114
- .build());
1115
- }
1116
- };
1117
-
1118
869
  // Collect request body
1119
870
  let (req_parts, body) = req.into_parts();
1120
- let collected_body = match http_body_util::BodyExt::collect(body).await {
1121
- Ok(collected) => collected.to_bytes(),
1122
- Err(err) => {
1123
- tracing::debug!(?err, "Failed to read request body");
1124
- Bytes::new()
1125
- }
1126
- };
1127
- let req_collected = hyper::Request::from_parts(
1128
- req_parts,
1129
- Full::<Bytes>::new(collected_body.clone()),
1130
- );
871
+ let req_body =
872
+ Limited::new(body, self.state.config.guard().http_max_request_body_size())
873
+ .collect()
874
+ .await
875
+ .map_err(|err| errors::InvalidRequestBody(err.to_string()).build())?
876
+ .to_bytes();
877
+ let req_collected =
878
+ hyper::Request::from_parts(req_parts, Full::<Bytes>::new(req_body));
1131
879
 
1132
880
  // Attempt request
1133
881
  let mut attempts = 0;
1134
- while attempts < max_attempts {
882
+ while attempts < req_ctx.retry.max_attempts {
1135
883
  attempts += 1;
1136
884
 
1137
- let res = handler
1138
- .handle_request(req_collected.clone(), request_context, request_id)
1139
- .await;
1140
- if should_retry_request(&res) {
885
+ let res = handler.handle_request(req_collected.clone(), req_ctx).await;
886
+ if utils::should_retry_request(&res) {
1141
887
  // Request connect error, might retry
1142
888
  tracing::debug!("Request attempt {attempts} failed (service unavailable)");
1143
889
 
1144
890
  // Use backoff and continue
1145
- let backoff = Self::calculate_backoff(attempts, initial_interval);
891
+ let backoff =
892
+ utils::calculate_backoff(attempts, req_ctx.retry.initial_interval);
1146
893
  tokio::time::sleep(backoff).await;
1147
894
 
1148
895
  // Refresh route (ignore cache) so subsequent requests can hit new target
1149
- let ResolveRouteOutput::CustomServe(new_handler) = self
1150
- .state
1151
- .resolve_route(
1152
- &host,
1153
- &path,
1154
- req_collected.method(),
1155
- self.state.port_type.clone(),
1156
- &req_headers,
1157
- true,
1158
- )
1159
- .await?
896
+ let ResolveRouteOutput::CustomServe(new_handler) =
897
+ self.state.resolve_route(req_ctx, true).await?
1160
898
  else {
1161
899
  bail!("resolved route does not match CustomServe");
1162
900
  };
@@ -1167,7 +905,7 @@ impl ProxyService {
1167
905
 
1168
906
  // Release in-flight counter and request ID before returning
1169
907
  self.state
1170
- .release_in_flight(client_ip, &actor_id, request_id)
908
+ .release_in_flight(req_ctx.client_ip, req_ctx.in_flight_request_id)
1171
909
  .await;
1172
910
  return res;
1173
911
  }
@@ -1175,130 +913,33 @@ impl ProxyService {
1175
913
  // If we get here, all attempts failed
1176
914
  // Release in-flight counter and request ID before returning error
1177
915
  self.state
1178
- .release_in_flight(client_ip, &actor_id, request_id)
916
+ .release_in_flight(req_ctx.client_ip, req_ctx.in_flight_request_id)
1179
917
  .await;
1180
918
  return Err(errors::RetryAttemptsExceeded {
1181
- attempts: max_attempts,
919
+ attempts: req_ctx.retry.max_attempts,
1182
920
  }
1183
921
  .build());
1184
922
  }
1185
923
  }
1186
924
  }
1187
925
 
1188
- /// Modifies the incoming request before it is proxied.
1189
- fn proxied_request_builder(
1190
- &self,
1191
- req_parts: &hyper::http::request::Parts,
1192
- target: &RouteTarget,
1193
- ) -> Result<hyper::http::request::Builder> {
1194
- let scheme = if target.port == 443 { "https" } else { "http" };
1195
-
1196
- // Bracket raw IPv6 hosts
1197
- let host = if target.host.contains(':') && !target.host.starts_with('[') {
1198
- format!("[{}]", target.host)
1199
- } else {
1200
- target.host.clone()
1201
- };
1202
-
1203
- // Ensure path starts with a leading slash
1204
- let path = if target.path.starts_with('/') {
1205
- target.path.clone()
1206
- } else {
1207
- format!("/{}", target.path)
1208
- };
1209
-
1210
- let url = Url::parse(&format!("{scheme}://{host}:{}{}", target.port, path))
1211
- .context("invalid scheme/host/port when building URL")?;
1212
-
1213
- // Build the proxied request
1214
- let mut builder = hyper::Request::builder()
1215
- .method(req_parts.method.clone())
1216
- .uri(url.to_string());
1217
-
1218
- // Modify proxy headers
1219
- let headers = builder
1220
- .headers_mut()
1221
- .expect("request builder unexpectedly in error state");
1222
-
1223
- headers.remove(X_RIVET_TARGET);
1224
- headers.remove(X_RIVET_ACTOR);
1225
- headers.remove(X_RIVET_TOKEN);
1226
-
1227
- add_proxy_headers_with_addr(headers, &req_parts.headers, self.remote_addr)?;
1228
-
1229
- Ok(builder)
1230
- }
1231
-
1232
926
  #[tracing::instrument(skip_all)]
1233
927
  async fn handle_websocket_upgrade(
1234
928
  &self,
1235
929
  req: Request<BodyIncoming>,
930
+ req_ctx: &mut RequestContext,
1236
931
  target: ResolveRouteOutput,
1237
- request_context: &mut RequestContext,
1238
- client_ip: std::net::IpAddr,
1239
- actor_id: Option<Id>,
1240
932
  ) -> Result<Response<ResponseBody>> {
1241
- // Parsed for retries later
1242
- let req_host = req
1243
- .headers()
1244
- .get(hyper::header::HOST)
1245
- .and_then(|h| h.to_str().ok())
1246
- .unwrap_or("unknown")
1247
- .to_string();
1248
- let req_path = req
1249
- .uri()
1250
- .path_and_query()
1251
- .map(|x| x.to_string())
1252
- .unwrap_or_else(|| req.uri().path().to_string());
1253
-
1254
- // Capture headers and method before request is consumed
1255
- let req_headers = req.headers().clone();
1256
- let req_method = req.method().clone();
1257
- let ray_id = req.extensions().get::<RequestIds>().map(|x| x.ray_id);
1258
-
1259
- // Get middleware config for this actor if it exists
1260
- let middleware_config = match &actor_id {
1261
- Some(actor_id) => {
1262
- self.state
1263
- .get_middleware_config(actor_id, &req_headers)
1264
- .await?
1265
- }
1266
- None => {
1267
- // Default middleware config for targets without actor_id
1268
- tracing::debug!("Using default middleware config (no actor_id)");
1269
- MiddlewareConfig {
1270
- rate_limit: RateLimitConfig {
1271
- requests: 100, // 100 requests
1272
- period: 60, // per 60 seconds
1273
- },
1274
- max_in_flight: MaxInFlightConfig {
1275
- amount: 20, // 20 concurrent requests
1276
- },
1277
- retry: RetryConfig {
1278
- max_attempts: 3, // 3 retry attempts
1279
- initial_interval: 100, // 100ms initial interval
1280
- },
1281
- timeout: TimeoutConfig {
1282
- request_timeout: 30, // 30 seconds for requests
1283
- },
1284
- }
1285
- }
1286
- };
1287
-
1288
- // Set up retry with backoff from middleware config
1289
- let max_attempts = middleware_config.retry.max_attempts;
1290
- let initial_interval = middleware_config.retry.initial_interval;
1291
-
1292
933
  // Log the headers for debugging
1293
934
  tracing::debug!("WebSocket upgrade request headers:");
1294
- for (name, value) in req.headers() {
935
+ for (name, value) in &req_ctx.headers {
1295
936
  if let Ok(val) = value.to_str() {
1296
937
  tracing::debug!(" {}: {}", name, val);
1297
938
  }
1298
939
  }
1299
940
 
1300
941
  // Handle WebSocket upgrade properly with hyper_tungstenite
1301
- tracing::debug!(%req_path, "Upgrading client connection to WebSocket");
942
+ tracing::debug!(path=%req_ctx.path, "Upgrading client connection to WebSocket");
1302
943
  let (client_response, client_ws) = match hyper_tungstenite::upgrade(req, None) {
1303
944
  Ok(x) => {
1304
945
  tracing::debug!("Client WebSocket upgrade successful");
@@ -1308,7 +949,7 @@ impl ProxyService {
1308
949
  tracing::error!(?err, "Failed to upgrade client WebSocket");
1309
950
  return Err(errors::ConnectionError {
1310
951
  error_message: format!("Failed to upgrade client WebSocket: {}", err),
1311
- remote_addr: self.remote_addr.to_string(),
952
+ remote_addr: req_ctx.remote_addr.to_string(),
1312
953
  }
1313
954
  .build());
1314
955
  }
@@ -1327,14 +968,17 @@ impl ProxyService {
1327
968
 
1328
969
  // Clone needed values for the spawned task
1329
970
  let state = self.state.clone();
1330
- let remote_addr = self.remote_addr;
1331
971
 
1332
972
  // Spawn a new task to handle the WebSocket bidirectional communication
1333
973
  match target {
1334
974
  ResolveRouteOutput::Target(mut target) => {
1335
975
  tracing::debug!("Spawning task to handle WebSocket communication");
976
+ let mut req_ctx = req_ctx.clone();
977
+
1336
978
  self.state.tasks.spawn(
1337
979
  async move {
980
+ let req_ctx = &mut req_ctx;
981
+
1338
982
  // Set up a timeout for the entire operation
1339
983
  let timeout_duration = Duration::from_secs(30); // 30 seconds timeout
1340
984
  tracing::debug!(
@@ -1369,7 +1013,7 @@ impl ProxyService {
1369
1013
 
1370
1014
  // Now attempt to connect to the upstream server
1371
1015
  tracing::debug!("Attempting connect to upstream WebSocket");
1372
- while attempts < max_attempts {
1016
+ while attempts < req_ctx.retry.max_attempts {
1373
1017
  attempts += 1;
1374
1018
 
1375
1019
  // Build the WebSocket URL using the url crate to properly handle IPv6 addresses
@@ -1414,7 +1058,7 @@ impl ProxyService {
1414
1058
  tracing::debug!(
1415
1059
  "WebSocket request attempt {}/{} to {}",
1416
1060
  attempts,
1417
- max_attempts,
1061
+ req_ctx.retry.max_attempts,
1418
1062
  target_url
1419
1063
  );
1420
1064
 
@@ -1428,10 +1072,9 @@ impl ProxyService {
1428
1072
  };
1429
1073
 
1430
1074
  // Add proxy headers to the websocket request
1431
- if let Err(err) = add_proxy_headers_with_addr(
1075
+ if let Err(err) = utils::add_proxy_headers_with_addr(
1432
1076
  ws_request.headers_mut(),
1433
- &req_headers,
1434
- remote_addr,
1077
+ req_ctx,
1435
1078
  ) {
1436
1079
  tracing::error!(
1437
1080
  ?err,
@@ -1485,21 +1128,23 @@ impl ProxyService {
1485
1128
  }
1486
1129
 
1487
1130
  // Check if we've reached max attempts
1488
- if attempts >= max_attempts {
1131
+ if attempts >= req_ctx.retry.max_attempts {
1489
1132
  tracing::debug!(
1490
1133
  "All {} WebSocket connection attempts failed",
1491
- max_attempts
1134
+ req_ctx.retry.max_attempts
1492
1135
  );
1493
1136
 
1494
1137
  // Send a close message to the client since we can't connect to upstream
1495
- tracing::debug!(
1496
- "Sending close message to client due to upstream connection failure"
1138
+ let err = errors::RetryAttemptsExceeded { attempts }.build();
1139
+ tracing::warn!(
1140
+ ?err,
1141
+ "sending close message to client due to upstream connection failure"
1497
1142
  );
1498
1143
  let (mut client_sink, _) = client_ws.split();
1499
1144
  match client_sink
1500
- .send(to_hyper_close(Some(err_to_close_frame(
1501
- errors::RetryAttemptsExceeded { attempts }.build(),
1502
- ray_id,
1145
+ .send(utils::to_hyper_close(Some(utils::err_to_close_frame(
1146
+ err,
1147
+ req_ctx.ray_id,
1503
1148
  ))))
1504
1149
  .await
1505
1150
  {
@@ -1532,7 +1177,8 @@ impl ProxyService {
1532
1177
  }
1533
1178
 
1534
1179
  // Use backoff for the next attempt
1535
- let backoff = Self::calculate_backoff(attempts, initial_interval);
1180
+ let backoff =
1181
+ utils::calculate_backoff(attempts, req_ctx.retry.initial_interval);
1536
1182
  tracing::debug!(
1537
1183
  "Waiting for {:?} before next connection attempt",
1538
1184
  backoff
@@ -1542,41 +1188,20 @@ impl ProxyService {
1542
1188
 
1543
1189
  // Resolve target again, this time ignoring cache. This makes sure
1544
1190
  // we always re-fetch the route on error
1545
- let new_target = state
1546
- .resolve_route(
1547
- &req_host,
1548
- &req_path,
1549
- &req_method,
1550
- state.port_type.clone(),
1551
- &req_headers,
1552
- true,
1553
- )
1554
- .await;
1191
+ let new_target = state.resolve_route(req_ctx, true).await;
1555
1192
 
1556
1193
  match new_target {
1557
1194
  Ok(ResolveRouteOutput::Target(new_target)) => {
1558
1195
  target = new_target;
1559
1196
  }
1560
- Ok(ResolveRouteOutput::Response(response)) => {
1561
- tracing::debug!(
1562
- status=?response.status,
1563
- message=?response.message,
1564
- docs=?response.docs,
1565
- "got response instead of websocket target",
1566
- );
1567
-
1568
- // Close the WebSocket connection with the response message
1569
- let _ = client_ws
1570
- .close(Some(str_to_close_frame(response.message.as_ref())))
1571
- .await;
1572
- return;
1573
- }
1574
1197
  Ok(ResolveRouteOutput::CustomServe(_)) => {
1198
+ let err = errors::WebSocketTargetChanged.build();
1199
+ tracing::warn!(
1200
+ ?err,
1201
+ "websocket target changed to custom serve"
1202
+ );
1575
1203
  let _ = client_ws
1576
- .close(Some(err_to_close_frame(
1577
- errors::WebSocketTargetChanged.build(),
1578
- ray_id,
1579
- )))
1204
+ .close(Some(utils::err_to_close_frame(err, req_ctx.ray_id)))
1580
1205
  .await;
1581
1206
  return;
1582
1207
  }
@@ -1658,7 +1283,7 @@ impl ProxyService {
1658
1283
  // Signal shutdown to other direction
1659
1284
  let _ = shutdown_tx.send(true);
1660
1285
 
1661
- to_hyper_close(frame)
1286
+ utils::to_hyper_close(frame)
1662
1287
  },
1663
1288
  hyper_tungstenite::tungstenite::Message::Frame(_) => {
1664
1289
  // Skip frames - they're an implementation detail
@@ -1809,7 +1434,7 @@ impl ProxyService {
1809
1434
  // Signal shutdown to other direction
1810
1435
  let _ = shutdown_tx.send(true);
1811
1436
 
1812
- to_hyper_close(frame)
1437
+ utils::to_hyper_close(frame)
1813
1438
  },
1814
1439
  tokio_tungstenite::tungstenite::Message::Frame(_) => {
1815
1440
  // Skip frames - they're an implementation detail
@@ -1879,7 +1504,7 @@ impl ProxyService {
1879
1504
 
1880
1505
  // Try to send a close frame - ignore errors as the connection might already be closed
1881
1506
  tracing::trace!("Attempting to send close message to client");
1882
- match sink.send(to_hyper_close(None)).await {
1507
+ match sink.send(utils::to_hyper_close(None)).await {
1883
1508
  Ok(_) => {
1884
1509
  tracing::trace!("Close message sent to client successfully")
1885
1510
  }
@@ -1908,34 +1533,14 @@ impl ProxyService {
1908
1533
  .instrument(tracing::info_span!("handle_ws_task_target")),
1909
1534
  );
1910
1535
  }
1911
- ResolveRouteOutput::Response(_) => unreachable!(),
1912
1536
  ResolveRouteOutput::CustomServe(mut handler) => {
1913
- tracing::debug!(%req_path, "Spawning task to handle WebSocket communication");
1914
- let mut request_context = request_context.clone();
1915
- let req_headers = req_headers.clone();
1537
+ tracing::debug!(path=%req_ctx.path, "Spawning task to handle WebSocket communication");
1916
1538
  let state = self.state.clone();
1917
- let req_path = req_path.clone();
1918
- let req_host = req_host.clone();
1919
- let req_method = req_method.clone();
1539
+ let mut req_ctx = req_ctx.clone();
1920
1540
 
1921
1541
  self.state.tasks.spawn(
1922
1542
  async move {
1923
- let request_id = match state
1924
- .acquire_in_flight(client_ip, &actor_id, &req_headers)
1925
- .await?
1926
- {
1927
- Some(id) => id,
1928
- None => {
1929
- return Err(errors::RateLimit {
1930
- actor_id,
1931
- method: req_method.to_string(),
1932
- path: req_path.clone(),
1933
- ip: client_ip.to_string(),
1934
- }
1935
- .build()
1936
- .into());
1937
- }
1938
- };
1543
+ let req_ctx = &mut req_ctx;
1939
1544
  let mut ws_hibernation_close = false;
1940
1545
  let mut after_hibernation = false;
1941
1546
  let mut attempts = 0u32;
@@ -1946,14 +1551,7 @@ impl ProxyService {
1946
1551
 
1947
1552
  loop {
1948
1553
  match handler
1949
- .handle_websocket(
1950
- ws_handle.clone(),
1951
- &req_headers,
1952
- &req_path,
1953
- &mut request_context,
1954
- request_id,
1955
- after_hibernation,
1956
- )
1554
+ .handle_websocket(req_ctx, ws_handle.clone(), after_hibernation)
1957
1555
  .await
1958
1556
  {
1959
1557
  Ok(close_frame) => {
@@ -1962,7 +1560,7 @@ impl ProxyService {
1962
1560
  // Send graceful close. This may fail if client already sent
1963
1561
  // close frame, which is normal.
1964
1562
  tracing::debug!(?close_frame, "sending close frame to client");
1965
- match ws_handle.send(to_hyper_close(close_frame)).await {
1563
+ match ws_handle.send(utils::to_hyper_close(close_frame)).await {
1966
1564
  Ok(_) => {
1967
1565
  tracing::debug!("close frame sent successfully");
1968
1566
  }
@@ -1997,7 +1595,7 @@ impl ProxyService {
1997
1595
  tracing::debug!(?err, "websocket handler error");
1998
1596
 
1999
1597
  // Denotes that the connection did not fail, but the downstream has closed
2000
- let ws_hibernate = is_ws_hibernate(&err);
1598
+ let ws_hibernate = utils::is_ws_hibernate(&err);
2001
1599
 
2002
1600
  if ws_hibernate {
2003
1601
  attempts = 0;
@@ -2021,8 +1619,8 @@ impl ProxyService {
2021
1619
  // (starting with the message that caused the hibernation to end)
2022
1620
  let res = handler
2023
1621
  .handle_websocket_hibernation(
1622
+ req_ctx,
2024
1623
  ws_handle.clone(),
2025
- request_id,
2026
1624
  )
2027
1625
  .await?;
2028
1626
 
@@ -2036,20 +1634,21 @@ impl ProxyService {
2036
1634
 
2037
1635
  ws_hibernation_close = true;
2038
1636
  }
2039
- } else if attempts > max_attempts
2040
- || !is_retryable_ws_error(&err)
1637
+ } else if attempts > req_ctx.retry.max_attempts
1638
+ || !utils::is_retryable_ws_error(&err)
2041
1639
  {
2042
1640
  tracing::debug!(
1641
+ ?err,
2043
1642
  ?attempts,
2044
- ?max_attempts,
2045
- "WebSocket failed"
1643
+ max_attempts=?req_ctx.retry.max_attempts,
1644
+ "websocket failed"
2046
1645
  );
2047
1646
 
2048
1647
  // Close WebSocket with error
2049
1648
  ws_handle
2050
- .send(to_hyper_close(Some(err_to_close_frame(
2051
- err, ray_id,
2052
- ))))
1649
+ .send(utils::to_hyper_close(Some(
1650
+ utils::err_to_close_frame(err, req_ctx.ray_id),
1651
+ )))
2053
1652
  .await?;
2054
1653
 
2055
1654
  // Flush to ensure close frame is sent
@@ -2060,9 +1659,9 @@ impl ProxyService {
2060
1659
 
2061
1660
  break;
2062
1661
  } else {
2063
- let backoff = ProxyService::calculate_backoff(
1662
+ let backoff = utils::calculate_backoff(
2064
1663
  attempts,
2065
- initial_interval,
1664
+ req_ctx.retry.initial_interval,
2066
1665
  );
2067
1666
 
2068
1667
  tracing::debug!(
@@ -2075,40 +1674,21 @@ impl ProxyService {
2075
1674
  }
2076
1675
 
2077
1676
  // Retry route resolution
2078
- match state
2079
- .resolve_route(
2080
- &req_host,
2081
- &req_path,
2082
- &req_method,
2083
- state.port_type.clone(),
2084
- &req_headers,
2085
- true,
2086
- )
2087
- .await
2088
- {
1677
+ match state.resolve_route(req_ctx, true).await {
2089
1678
  Ok(ResolveRouteOutput::CustomServe(new_handler)) => {
2090
1679
  handler = new_handler;
2091
1680
  continue;
2092
1681
  }
2093
- Ok(ResolveRouteOutput::Response(response)) => {
2094
- ws_handle
2095
- .send(to_hyper_close(Some(str_to_close_frame(
2096
- response.message.as_ref(),
2097
- ))))
2098
- .await?;
2099
-
2100
- // Flush to ensure close frame is sent
2101
- ws_handle.flush().await?;
2102
-
2103
- // Keep TCP connection open briefly to allow client to process close
2104
- tokio::time::sleep(WEBSOCKET_CLOSE_LINGER).await;
2105
- }
2106
1682
  Ok(ResolveRouteOutput::Target(_)) => {
1683
+ let err = errors::WebSocketTargetChanged.build();
1684
+ tracing::warn!(
1685
+ ?err,
1686
+ "websocket target changed to target"
1687
+ );
2107
1688
  ws_handle
2108
- .send(to_hyper_close(Some(err_to_close_frame(
2109
- errors::WebSocketTargetChanged.build(),
2110
- ray_id,
2111
- ))))
1689
+ .send(utils::to_hyper_close(Some(
1690
+ utils::err_to_close_frame(err, req_ctx.ray_id),
1691
+ )))
2112
1692
  .await?;
2113
1693
 
2114
1694
  // Flush to ensure close frame is sent
@@ -2120,10 +1700,14 @@ impl ProxyService {
2120
1700
  break;
2121
1701
  }
2122
1702
  Err(err) => {
1703
+ tracing::warn!(
1704
+ ?err,
1705
+ "closing websocket due to route resolution error"
1706
+ );
2123
1707
  ws_handle
2124
- .send(to_hyper_close(Some(err_to_close_frame(
2125
- err, ray_id,
2126
- ))))
1708
+ .send(utils::to_hyper_close(Some(
1709
+ utils::err_to_close_frame(err, req_ctx.ray_id),
1710
+ )))
2127
1711
  .await?;
2128
1712
 
2129
1713
  // Flush to ensure close frame is sent
@@ -2141,7 +1725,7 @@ impl ProxyService {
2141
1725
 
2142
1726
  // Release in-flight counter and request ID when task completes
2143
1727
  state
2144
- .release_in_flight(client_ip, &actor_id, request_id)
1728
+ .release_in_flight(req_ctx.client_ip, req_ctx.in_flight_request_id)
2145
1729
  .await;
2146
1730
 
2147
1731
  Ok(())
@@ -2173,318 +1757,12 @@ impl ProxyService {
2173
1757
  }
2174
1758
  }
2175
1759
 
2176
- impl ProxyService {
2177
- // Process an individual request
2178
- #[tracing::instrument(name = "guard_request", skip_all, fields(ray_id, req_id))]
2179
- pub async fn process(&self, mut req: Request<BodyIncoming>) -> Result<Response<ResponseBody>> {
2180
- let start_time = Instant::now();
2181
-
2182
- let request_ids = RequestIds::new(self.state.config.dc_label());
2183
- req.extensions_mut().insert(request_ids);
2184
-
2185
- tracing::Span::current()
2186
- .record("req_id", request_ids.req_id.to_string())
2187
- .record("ray_id", request_ids.ray_id.to_string());
2188
-
2189
- // Create request context for analytics tracking
2190
- let mut request_context =
2191
- RequestContext::new(self.state.clickhouse_inserter.clone(), request_ids);
2192
-
2193
- // Extract request information for logging and analytics before consuming the request
2194
- let incoming_ray_id = req
2195
- .headers()
2196
- .get(X_RIVET_RAY_ID)
2197
- .and_then(|h| h.to_str().ok())
2198
- .and_then(|id| Id::parse(id).ok());
2199
- let host = req
2200
- .headers()
2201
- .get(hyper::header::HOST)
2202
- .and_then(|h| h.to_str().ok())
2203
- .unwrap_or("unknown")
2204
- .to_string();
2205
- let uri_string = req.uri().to_string();
2206
- let path = req
2207
- .uri()
2208
- .path_and_query()
2209
- .map(|x| x.to_string())
2210
- .unwrap_or_else(|| req.uri().path().to_string());
2211
- let method = req.method().clone();
2212
-
2213
- let user_agent = req
2214
- .headers()
2215
- .get(hyper::header::USER_AGENT)
2216
- .and_then(|h| h.to_str().ok())
2217
- .map(|s| s.to_string());
2218
-
2219
- // Populate request context with available data
2220
- request_context.client_ip = Some(self.remote_addr.ip());
2221
- request_context.client_request_host = Some(host.clone());
2222
- request_context.client_request_method = Some(method.to_string());
2223
- request_context.client_request_path = Some(req.uri().path().to_string());
2224
- request_context.client_request_protocol = Some(format!("{:?}", req.version()));
2225
- request_context.client_request_scheme =
2226
- Some(req.uri().scheme_str().unwrap_or("http").to_string());
2227
- request_context.client_request_uri = Some(path.clone());
2228
- request_context.client_src_port = Some(self.remote_addr.port());
2229
-
2230
- if let Some(referer) = req
2231
- .headers()
2232
- .get(hyper::header::REFERER)
2233
- .and_then(|h| h.to_str().ok())
2234
- {
2235
- request_context.client_request_referer = Some(referer.to_string());
2236
- }
2237
-
2238
- if let Some(ua) = &user_agent {
2239
- request_context.client_request_user_agent = Some(ua.clone());
2240
- }
2241
-
2242
- if let Some(requested_with) = req
2243
- .headers()
2244
- .get("x-requested-with")
2245
- .and_then(|h| h.to_str().ok())
2246
- {
2247
- request_context.client_x_requested_with = Some(requested_with.to_string());
2248
- }
2249
-
2250
- // TLS information would be set here if available (for HTTPS connections)
2251
- // This requires TLS connection introspection and is marked for future enhancement
2252
-
2253
- // Debug log request information with structured fields (Apache-like access log)
2254
- tracing::debug!(
2255
- ?incoming_ray_id,
2256
- ray_id=?request_ids.ray_id,
2257
- req_id=?request_ids.req_id,
2258
- method = %method,
2259
- path = %path,
2260
- host = %host,
2261
- remote_addr = %self.remote_addr,
2262
- uri = %uri_string,
2263
- protocol = ?self.state.port_type,
2264
- user_agent = ?user_agent,
2265
- "Request received"
2266
- );
2267
-
2268
- let is_websocket = hyper_tungstenite::is_upgrade_request(&req);
2269
-
2270
- // Used for ws error proxying later
2271
- let mut mock_req_builder = Request::builder()
2272
- .method(req.method().clone())
2273
- .uri(req.uri().clone())
2274
- .version(req.version().clone());
2275
- if let Some(headers) = mock_req_builder.headers_mut() {
2276
- *headers = req.headers().clone();
2277
- }
2278
- if let Some(extensions) = mock_req_builder.extensions_mut() {
2279
- *extensions = req.extensions().clone();
2280
- }
2281
- let mock_req = mock_req_builder.body(())?;
2282
-
2283
- // Process the request
2284
- let mut res = match self
2285
- .handle_request(req, start_time, &mut request_context)
2286
- .await
2287
- {
2288
- Ok(res) => res,
2289
- Err(err) => {
2290
- // Log the error
2291
- tracing::error!(?err, "Request failed");
2292
-
2293
- metrics::PROXY_REQUEST_ERROR
2294
- .add(1, &[KeyValue::new("error_type", err.to_string())]);
2295
-
2296
- // If we receive an error during a websocket request, we attempt to open the websocket anyway
2297
- // so we can send the error via websocket instead of http. Most websocket clients don't handle
2298
- // HTTP errors in a meaningful way resulting in unhelpful errors for the user
2299
- if is_websocket {
2300
- tracing::debug!("Upgrading client connection to WebSocket for error proxy");
2301
- match hyper_tungstenite::upgrade(mock_req, None) {
2302
- Ok((client_response, client_ws)) => {
2303
- tracing::debug!("Client WebSocket upgrade for error proxy successful");
2304
-
2305
- self.state.tasks.spawn(
2306
- async move {
2307
- let ws_handle = match WebSocketHandle::new(client_ws).await {
2308
- Ok(ws_handle) => ws_handle,
2309
- Err(err) => {
2310
- tracing::debug!(
2311
- ?err,
2312
- "failed initiating websocket handle for error proxy"
2313
- );
2314
- return;
2315
- }
2316
- };
2317
- let frame = err_to_close_frame(err, Some(request_ids.ray_id));
2318
-
2319
- // Manual conversion to handle different tungstenite versions
2320
- let code_num: u16 = frame.code.into();
2321
- let reason = frame.reason.clone();
2322
-
2323
- if let Err(err) = ws_handle
2324
- .send(tokio_tungstenite::tungstenite::Message::Close(Some(
2325
- tokio_tungstenite::tungstenite::protocol::CloseFrame {
2326
- code: code_num.into(),
2327
- reason,
2328
- },
2329
- )))
2330
- .await
2331
- {
2332
- tracing::debug!(
2333
- ?err,
2334
- "failed sending websocket error proxy"
2335
- );
2336
- }
2337
- }
2338
- .instrument(
2339
- tracing::info_span!("ws_error_proxy_task", ?request_ids.ray_id),
2340
- ),
2341
- );
2342
-
2343
- // Return the response that will upgrade the client connection
2344
- // For proper WebSocket handshaking, we need to preserve the original response
2345
- // structure but convert it to our expected return type without modifying its content
2346
- tracing::debug!(
2347
- "Returning WebSocket upgrade response for error proxy to client"
2348
- );
2349
- // Extract the parts from the response but preserve all headers and status
2350
- let (mut parts, _) = client_response.into_parts();
2351
-
2352
- // Add Sec-WebSocket-Protocol header to the response
2353
- // Many WebSocket clients (e.g. node-ws & Cloudflare) require a protocol in the response
2354
- parts.headers.insert(
2355
- "sec-websocket-protocol",
2356
- hyper::header::HeaderValue::from_static("rivet"),
2357
- );
2358
-
2359
- // Create a new response with an empty body - WebSocket upgrades don't need a body
2360
- Response::from_parts(
2361
- parts,
2362
- ResponseBody::Full(Full::<Bytes>::new(Bytes::new())),
2363
- )
2364
- }
2365
- Err(err) => {
2366
- tracing::error!(
2367
- ?err,
2368
- "Failed to upgrade client WebSocket for error proxy"
2369
- );
2370
-
2371
- err_into_response(
2372
- errors::ConnectionError {
2373
- error_message: format!(
2374
- "Failed to upgrade client WebSocket for error proxy: {}",
2375
- err
2376
- ),
2377
- remote_addr: self.remote_addr.to_string(),
2378
- }
2379
- .build(),
2380
- )?
2381
- }
2382
- }
2383
- } else {
2384
- err_into_response(err)?
2385
- }
2386
- }
2387
- };
2388
-
2389
- if is_websocket && res.status() != StatusCode::SWITCHING_PROTOCOLS {
2390
- tracing::debug!("returned non-101 response to websocket");
2391
- }
2392
-
2393
- // Add ray_id to response headers
2394
- if let Ok(ray_id_value) = request_ids.ray_id.to_string().parse() {
2395
- if let Some(existing_ray_id_value) = res
2396
- .headers()
2397
- .get(X_RIVET_RAY_ID)
2398
- .and_then(|h| h.to_str().ok())
2399
- {
2400
- if ray_id_value != existing_ray_id_value {
2401
- tracing::warn!(
2402
- expected_ray_id=%request_ids.ray_id,
2403
- received_ray_id=%existing_ray_id_value,
2404
- "downstream service set ray id header to a different value",
2405
- );
2406
- }
2407
- }
2408
-
2409
- res.headers_mut().insert(X_RIVET_RAY_ID, ray_id_value);
2410
- }
2411
-
2412
- let status = res.status().as_u16();
2413
-
2414
- // Update request context with response details
2415
- request_context.guard_response_status = Some(status);
2416
- request_context.service_response_status = Some(status);
2417
-
2418
- if let Some(content_type) = res
2419
- .headers()
2420
- .get(hyper::header::CONTENT_TYPE)
2421
- .and_then(|h| h.to_str().ok())
2422
- {
2423
- request_context.guard_response_content_type = Some(content_type.to_string());
2424
- }
2425
-
2426
- if let Some(expires) = res
2427
- .headers()
2428
- .get(hyper::header::EXPIRES)
2429
- .and_then(|h| h.to_str().ok())
2430
- {
2431
- request_context.service_response_http_expires = Some(expires.to_string());
2432
- }
2433
-
2434
- if let Some(last_modified) = res
2435
- .headers()
2436
- .get(hyper::header::LAST_MODIFIED)
2437
- .and_then(|h| h.to_str().ok())
2438
- {
2439
- request_context.service_response_http_last_modified = Some(last_modified.to_string());
2440
- }
2441
-
2442
- // Set timing information
2443
- request_context.service_response_duration_ms =
2444
- Some(start_time.elapsed().as_millis() as u32);
2445
-
2446
- // Insert analytics event asynchronously
2447
- let mut context_clone = request_context.clone();
2448
- tokio::spawn(
2449
- async move {
2450
- if let Err(error) = context_clone.insert_event().await {
2451
- tracing::warn!(?error, "failed to insert guard analytics event");
2452
- }
2453
- }
2454
- .instrument(tracing::info_span!("insert_event_task")),
2455
- );
2456
-
2457
- let content_length = res
2458
- .headers()
2459
- .get(hyper::header::CONTENT_LENGTH)
2460
- .and_then(|h| h.to_str().ok())
2461
- .and_then(|s| s.parse::<usize>().ok())
2462
- .unwrap_or(0);
2463
-
2464
- // Log information about the completed request
2465
- tracing::debug!(
2466
- ?incoming_ray_id,
2467
- ray_id=?request_ids.ray_id,
2468
- req_id=?request_ids.req_id,
2469
- method = %method,
2470
- path = %path,
2471
- host = %host,
2472
- remote_addr = %self.remote_addr,
2473
- status = %status,
2474
- content_length = %content_length,
2475
- "Request completed"
2476
- );
2477
-
2478
- Ok(res)
2479
- }
2480
- }
2481
-
2482
1760
  impl Clone for ProxyService {
2483
1761
  fn clone(&self) -> Self {
2484
1762
  Self {
2485
1763
  state: self.state.clone(),
2486
1764
  remote_addr: self.remote_addr,
2487
- client: self.client.clone(),
1765
+ connection_start: self.connection_start,
2488
1766
  }
2489
1767
  }
2490
1768
  }
@@ -2499,18 +1777,8 @@ impl ProxyServiceFactory {
2499
1777
  config: rivet_config::Config,
2500
1778
  routing_fn: RoutingFn,
2501
1779
  cache_key_fn: CacheKeyFn,
2502
- middleware_fn: MiddlewareFn,
2503
- port_type: PortType,
2504
- clickhouse_inserter: Option<clickhouse_inserter::ClickHouseInserterHandle>,
2505
1780
  ) -> Self {
2506
- let state = Arc::new(ProxyState::new(
2507
- config,
2508
- routing_fn,
2509
- cache_key_fn,
2510
- middleware_fn,
2511
- port_type,
2512
- clickhouse_inserter,
2513
- ));
1781
+ let state = Arc::new(ProxyState::new(config, routing_fn, cache_key_fn));
2514
1782
  Self { state }
2515
1783
  }
2516
1784
 
@@ -2522,178 +1790,8 @@ impl ProxyServiceFactory {
2522
1790
  pub async fn wait_idle(&self) {
2523
1791
  self.state.tasks.wait_idle().await
2524
1792
  }
2525
- }
2526
-
2527
- fn add_proxy_headers_with_addr(
2528
- headers: &mut hyper::HeaderMap,
2529
- original_headers: &hyper::HeaderMap,
2530
- remote_addr: SocketAddr,
2531
- ) -> Result<()> {
2532
- // Copy headers except Host
2533
- for (key, value) in original_headers.iter() {
2534
- if key != hyper::header::HOST {
2535
- headers.insert(key.clone(), value.clone());
2536
- }
2537
- }
2538
-
2539
- // Add X-Forwarded-For header
2540
- if let Some(existing) = original_headers.get(X_FORWARDED_FOR) {
2541
- if let Ok(forwarded) = existing.to_str() {
2542
- if !forwarded.contains(&remote_addr.ip().to_string()) {
2543
- headers.insert(
2544
- X_FORWARDED_FOR,
2545
- hyper::header::HeaderValue::from_str(&format!(
2546
- "{}, {}",
2547
- forwarded,
2548
- remote_addr.ip()
2549
- ))?,
2550
- );
2551
- }
2552
- }
2553
- } else {
2554
- headers.insert(
2555
- X_FORWARDED_FOR,
2556
- hyper::header::HeaderValue::from_str(&remote_addr.ip().to_string())?,
2557
- );
2558
- }
2559
-
2560
- Ok(())
2561
- }
2562
-
2563
- fn err_into_response(err: anyhow::Error) -> Result<Response<ResponseBody>> {
2564
- let (status, error_response) =
2565
- if let Some(rivet_err) = err.chain().find_map(|x| x.downcast_ref::<RivetError>()) {
2566
- let status = match (rivet_err.group(), rivet_err.code()) {
2567
- ("api", "not_found") => StatusCode::NOT_FOUND,
2568
- ("api", "unauthorized") => StatusCode::UNAUTHORIZED,
2569
- ("api", "forbidden") => StatusCode::FORBIDDEN,
2570
- ("guard", "rate_limit") => StatusCode::TOO_MANY_REQUESTS,
2571
- ("guard", "upstream_error") => StatusCode::BAD_GATEWAY,
2572
- ("guard", "routing_error") => StatusCode::BAD_GATEWAY,
2573
- ("guard", "request_timeout") => StatusCode::GATEWAY_TIMEOUT,
2574
- ("guard", "retry_attempts_exceeded") => StatusCode::BAD_GATEWAY,
2575
- ("guard", "actor_not_found") => StatusCode::NOT_FOUND,
2576
- ("guard", "actor_destroyed") => StatusCode::NOT_FOUND,
2577
- ("guard", "service_unavailable") => StatusCode::SERVICE_UNAVAILABLE,
2578
- ("guard", "actor_ready_timeout") => StatusCode::SERVICE_UNAVAILABLE,
2579
- ("guard", "no_route") => StatusCode::NOT_FOUND,
2580
- _ => StatusCode::BAD_REQUEST,
2581
- };
2582
-
2583
- (status, ErrorResponse::from(rivet_err))
2584
- } else if let Some(raw_err) = err
2585
- .chain()
2586
- .find_map(|x| x.downcast_ref::<RawErrorResponse>())
2587
- {
2588
- (raw_err.0, raw_err.1.clone())
2589
- } else {
2590
- (
2591
- StatusCode::INTERNAL_SERVER_ERROR,
2592
- ErrorResponse::from(&RivetError {
2593
- schema: &rivet_error::INTERNAL_ERROR,
2594
- meta: None,
2595
- message: None,
2596
- }),
2597
- )
2598
- };
2599
-
2600
- let body_json = serde_json::to_vec(&error_response)?;
2601
- let bytes = Bytes::from(body_json);
2602
-
2603
- Response::builder()
2604
- .status(status)
2605
- .header(hyper::header::CONTENT_TYPE, "application/json")
2606
- .body(ResponseBody::Full(Full::new(bytes)))
2607
- .map_err(Into::into)
2608
- }
2609
-
2610
- fn should_retry_request(res: &Result<Response<ResponseBody>>) -> bool {
2611
- match res {
2612
- Ok(resp) => should_retry_request_inner(resp.status(), resp.headers()),
2613
- Err(err) => {
2614
- if let Some(rivet_err) = err.chain().find_map(|x| x.downcast_ref::<RivetError>()) {
2615
- rivet_err.group() == "guard" && rivet_err.code() == "service_unavailable"
2616
- } else {
2617
- false
2618
- }
2619
- }
2620
- }
2621
- }
2622
1793
 
2623
- // Determine if a response should trigger a retry: 503 + x-rivet-error
2624
- fn should_retry_request_inner(status: StatusCode, headers: &hyper::HeaderMap) -> bool {
2625
- status == StatusCode::SERVICE_UNAVAILABLE && headers.contains_key(X_RIVET_ERROR)
2626
- }
2627
-
2628
- // Determine if a websocket error is retryable (e.g., transient UPS/tunnel issues)
2629
- fn is_retryable_ws_error(err: &anyhow::Error) -> bool {
2630
- if let Some(rivet_err) = err.chain().find_map(|x| x.downcast_ref::<RivetError>()) {
2631
- rivet_err.group() == "guard" && rivet_err.code() == "websocket_service_unavailable"
2632
- } else {
2633
- false
2634
- }
2635
- }
2636
-
2637
- pub fn is_ws_hibernate(err: &anyhow::Error) -> bool {
2638
- if let Some(rivet_err) = err.chain().find_map(|x| x.downcast_ref::<RivetError>()) {
2639
- rivet_err.group() == "guard" && rivet_err.code() == "websocket_service_hibernate"
2640
- } else {
2641
- false
2642
- }
2643
- }
2644
-
2645
- fn str_to_close_frame(err: &str) -> CloseFrame {
2646
- // NOTE: reason cannot be more than 123 bytes as per the WS protocol spec
2647
- let reason = rivet_util::safe_slice(err, 0, 123).into();
2648
-
2649
- CloseFrame {
2650
- code: CloseCode::Error,
2651
- reason,
2652
- }
2653
- }
2654
-
2655
- fn err_to_close_frame(err: anyhow::Error, ray_id: Option<Id>) -> CloseFrame {
2656
- let rivet_err = err
2657
- .chain()
2658
- .find_map(|x| x.downcast_ref::<RivetError>())
2659
- .cloned()
2660
- .unwrap_or_else(|| RivetError::from(&INTERNAL_ERROR));
2661
-
2662
- let code = match (rivet_err.group(), rivet_err.code()) {
2663
- ("ws", "connection_closed") | ("ws", "eviction") => CloseCode::Normal,
2664
- _ => CloseCode::Error,
2665
- };
2666
-
2667
- let reason = if let Some(ray_id) = ray_id {
2668
- format!("{}.{}#{}", rivet_err.group(), rivet_err.code(), ray_id)
2669
- } else {
2670
- format!("{}.{}", rivet_err.group(), rivet_err.code())
2671
- };
2672
-
2673
- // NOTE: reason cannot be more than 123 bytes as per the WS protocol
2674
- let reason = rivet_util::safe_slice(&reason, 0, 123).into();
2675
-
2676
- CloseFrame { code, reason }
2677
- }
2678
-
2679
- fn to_hyper_close(frame: Option<CloseFrame>) -> hyper_tungstenite::tungstenite::Message {
2680
- if let Some(frame) = frame {
2681
- // Manual conversion to handle different tungstenite versions
2682
- let code_num: u16 = frame.code.into();
2683
- let reason = frame.reason.clone();
2684
-
2685
- tokio_tungstenite::tungstenite::Message::Close(Some(
2686
- tokio_tungstenite::tungstenite::protocol::CloseFrame {
2687
- code: code_num.into(),
2688
- reason,
2689
- },
2690
- ))
2691
- } else {
2692
- tokio_tungstenite::tungstenite::Message::Close(Some(
2693
- tokio_tungstenite::tungstenite::protocol::CloseFrame {
2694
- code: CloseCode::Normal,
2695
- reason: "ws.closed".into(),
2696
- },
2697
- ))
1794
+ pub fn remaining_tasks(&self) -> usize {
1795
+ self.state.tasks.remaining_tasks()
2698
1796
  }
2699
1797
  }