| ... | @@ -4,6 +4,7 @@ import * as Effect from "effect/Effect"; | ... | @@ -4,6 +4,7 @@ import * as Effect from "effect/Effect"; |
| 4 | import * as Layer from "effect/Layer"; | 4 | import * as Layer from "effect/Layer"; |
| 5 | import * as Redacted from "effect/Redacted"; | 5 | import * as Redacted from "effect/Redacted"; |
| 6 | import * as TestClock from "effect/testing/TestClock"; | 6 | import * as TestClock from "effect/testing/TestClock"; |
| | 7 | import * as Tracer from "effect/Tracer"; |
| 7 | | 8 | |
| 8 | import * as RelayConfiguration from "../Config.ts"; | 9 | import * as RelayConfiguration from "../Config.ts"; |
| 9 | import * as ManagedEndpointAllocations from "./ManagedEndpointAllocations.ts"; | 10 | import * as ManagedEndpointAllocations from "./ManagedEndpointAllocations.ts"; |
| ... | @@ -574,6 +575,54 @@ describe("ManagedEndpointReaper", () => { | ... | @@ -574,6 +575,54 @@ describe("ManagedEndpointReaper", () => { |
| 574 | }).pipe(Effect.provide(state.layer)); | 575 | }).pipe(Effect.provide(state.layer)); |
| 575 | }); | 576 | }); |
| 576 | | 577 | |
| | 578 | it.effect("records dry-run counters on the sweep span", () => { |
| | 579 | const spans: Array<Tracer.NativeSpan> = []; |
| | 580 | const tracer = Tracer.make({ |
| | 581 | span: (options) => { |
| | 582 | const span = new Tracer.NativeSpan(options); |
| | 583 | spans.push(span); |
| | 584 | return span; |
| | 585 | }, |
| | 586 | }); |
| | 587 | const expired = [ |
| | 588 | tunnel({ |
| | 589 | id: "recoverable", |
| | 590 | suffix: "aaaaaaaaaaaaaaaa", |
| | 591 | status: "down", |
| | 592 | timestamp: "2026-08-25T11:00:00.000Z", |
| | 593 | }), |
| | 594 | tunnel({ |
| | 595 | id: "legacy", |
| | 596 | suffix: "bbbbbbbbbbbbbbbb", |
| | 597 | status: "down", |
| | 598 | timestamp: "2026-08-25T11:00:00.000Z", |
| | 599 | }), |
| | 600 | ]; |
| | 601 | const state = harness({ |
| | 602 | cleanupMode: "dry-run", |
| | 603 | tunnels: expired, |
| | 604 | allocations: [ |
| | 605 | allocation({ tunnelId: "recoverable", recoveryEnabled: true }), |
| | 606 | allocation({ tunnelId: "legacy", recoveryEnabled: false }), |
| | 607 | ], |
| | 608 | }); |
| | 609 | |
| | 610 | return Effect.gen(function* () { |
| | 611 | yield* TestClock.setTime(NOW_MILLIS); |
| | 612 | const reaper = yield* ManagedEndpointReaper.ManagedEndpointReaper; |
| | 613 | yield* reaper.sweep; |
| | 614 | const sweepSpan = spans.find((span) => span.name === "relay.managed_endpoint_reaper.sweep"); |
| | 615 | expect(Object.fromEntries(sweepSpan?.attributes ?? [])).toMatchObject({ |
| | 616 | "relay.managed_endpoint_reaper.mode": "dry-run", |
| | 617 | "relay.managed_endpoint_reaper.scanned": 2, |
| | 618 | "relay.managed_endpoint_reaper.wouldDelete": 1, |
| | 619 | "relay.managed_endpoint_reaper.skippedLegacy": 1, |
| | 620 | "relay.managed_endpoint_reaper.deleted": 0, |
| | 621 | }); |
| | 622 | expect(state.deleted).toEqual([]); |
| | 623 | }).pipe(Effect.provide(state.layer), Effect.withTracer(tracer)); |
| | 624 | }); |
| | 625 | |
| 577 | it.effect("does no Cloudflare work while cleanup is off", () => { | 626 | it.effect("does no Cloudflare work while cleanup is off", () => { |
| 578 | const state = harness({ | 627 | const state = harness({ |
| 579 | cleanupMode: "off", | 628 | cleanupMode: "off", |