Unified · Split
| @@ -1,5 +1,6 @@ | |||
| 1 | import { createConnection } from "node:net"; | ||
| 1 | import * as NodeHttpServer from "@effect/platform-node/NodeHttpServer"; | 2 | import * as NodeHttpServer from "@effect/platform-node/NodeHttpServer"; |
| 2 | import { Context, Data, Effect, Layer, Predicate, Scope as EffectScope } from "effect"; | 3 | import { Context, Data, Effect, Layer, Predicate, Schedule, Scope as EffectScope } from "effect"; |
| 3 | import { | 4 | import { |
| 4 | HttpClient, | 5 | HttpClient, |
| 5 | HttpRouter, | 6 | HttpRouter, |
| @@ -109,6 +110,16 @@ const makeTestHttpServer = ( · 103 unmodified lines | |||
| 109 | return yield* new TestHttpServerAddressError({ address }); | 110 | return yield* new TestHttpServerAddressError({ address }); |
| 110 | } | 111 | } |
| 111 | const client = Context.get(context, HttpClient.HttpClient); | 112 | const client = Context.get(context, HttpClient.HttpClient); |
| 113 | // Under a loaded machine the listen callback can fire before the socket | ||
| 114 | // reliably accepts; probe at the TCP level (no HTTP request, so handlers | ||
| 115 | // that record requests never see it) until a connect succeeds. | ||
| 116 | yield* Effect.callback<void, TestHttpServerServeError>((resume) => { | ||
| 117 | const socket = createConnection({ host: "127.0.0.1", port: address.port }, () => { | ||
| 118 | socket.end(); | ||
| 119 | resume(Effect.void); | ||
| 120 | }); | ||
| 121 | socket.on("error", (cause) => resume(Effect.fail(new TestHttpServerServeError({ cause })))); | ||
| 122 | }).pipe(Effect.retry(Schedule.both(Schedule.spaced("10 millis"), Schedule.recurs(100)))); | ||
| 112 | const baseUrl = `http://127.0.0.1:${address.port}`; | 123 | const baseUrl = `http://127.0.0.1:${address.port}`; |
| 113 | return { | 124 | return { |
| 114 | baseUrl, | 125 | baseUrl, |