# Files changed · PR \#5198 · pingdotgg/t3code

[View on GitCafe](https://git.cafe/pingdotgg/t3code/pull/5198/diffs)

Repository: [pingdotgg/t3code](https://git.cafe/pingdotgg/t3code)

Visibility: public

[fix\(client-runtime\): tolerate transient foreground probe timeouts](https://git.cafe/pingdotgg/t3code/pull/5198.md)

Version: 1

Head commit: 3fdbd155b93f90d9b9e24ca89ed010b3ff097887

Base commit: d3037064e61a9f059eafbd4f9869679779bd2a7c

Comparison base: d3037064e61a9f059eafbd4f9869679779bd2a7c

Showing up to 20 entries from this revision. If the pull request changes, reopen the first page before continuing.

## packages/client-runtime/src/connection/supervisor.test.ts

Status: modified; +83; −0

```diff
@@ -949,6 +949,89 @@
     }).pipe(Effect.provide(TestClock.layer())),
   );
 
+  it.effect("reconnects only after consecutive foreground liveness probe timeouts", () =>
+    Effect.gen(function* () {
+      const firstProbeStarted = yield* Deferred.make<void>();
+      const secondProbeStarted = yield* Deferred.make<void>();
+      const probeCount = yield* Ref.make(0);
+      const harness = yield* makeHarness({
+        probe: () =>
+          Ref.updateAndGet(probeCount, (count) => count + 1).pipe(
+            Effect.tap((count) =>
+              Deferred.succeed(count === 1 ? firstProbeStarted : secondProbeStarted, undefined),
+            ),
+            Effect.andThen(Effect.never),
+          ),
+      });
+      const supervisor = yield* EnvironmentSupervisor.make(TARGET_ENTRY, {
+        initiallyDesired: true,
+      }).pipe(Effect.provide(harness.dependencies));
+
+      yield* awaitState(supervisor.state, (state) => state.phase === "connected");
+      yield* harness.wake("application-active");
+      yield* Deferred.await(firstProbeStarted);
+      yield* TestClock.adjust("15 seconds");
+      yield* Effect.yieldNow;
+
+      expect((yield* SubscriptionRef.get(supervisor.state)).phase).toBe("connected");
+      expect(yield* Ref.get(harness.sessionCount)).toBe(1);
+      expect(yield* Ref.get(harness.releaseCount)).toBe(0);
+
+      yield* harness.wake("application-active");
+      yield* Deferred.await(secondProbeStarted);
+      yield* TestClock.adjust("15 seconds");
+      yield* awaitState(supervisor.state, (state) => state.phase === "backoff");
+
+      expect(yield* Ref.get(harness.sessionCount)).toBe(1);
+      expect(yield* Ref.get(harness.releaseCount)).toBe(1);
+    }).pipe(Effect.provide(TestClock.layer())),
+  );
+
+  it.effect("resets the foreground probe timeout count after a successful probe", () =>
+    Effect.gen(function* () {
+      const firstProbeStarted = yield* Deferred.make<void>();
+      const secondProbeStarted = yield* Deferred.make<void>();
+      const thirdProbeStarted = yield* Deferred.make<void>();
+      const probeCount = yield* Ref.make(0);
+      const harness = yield* makeHarness({
+        probe: () =>
+          Ref.updateAndGet(probeCount, (count) => count + 1).pipe(
+            Effect.tap((count) =>
+              count === 1
+                ? Deferred.succeed(firstProbeStarted, undefined)
+                : count === 2
+                  ? Deferred.succeed(secondProbeStarted, undefined)
+                  : count === 3
+                    ? Deferred.succeed(thirdProbeStarted, undefined)
+                    : Effect.void,
+            ),
+            Effect.flatMap((count) => (count === 2 ? Effect.void : Effect.never)),
+          ),
+      });
+      const supervisor = yield* EnvironmentSupervisor.make(TARGET_ENTRY, {
+        initiallyDesired: true,
+      }).pipe(Effect.provide(harness.dependencies));
+
+      yield* awaitState(supervisor.state, (state) => state.phase === "connected");
+      yield* harness.wake("application-active");
+      yield* Deferred.await(firstProbeStarted);
+      yield* TestClock.adjust("15 seconds");
+
+      yield* harness.wake("application-active");
+      yield* Deferred.await(secondProbeStarted);
+      yield* Effect.yieldNow;
+
+      yield* harness.wake("application-active");
+      yield* Deferred.await(thirdProbeStarted);
+      yield* TestClock.adjust("15 seconds");
+      yield* Effect.yieldNow;
+
+      expect((yield* SubscriptionRef.get(supervisor.state)).phase).toBe("connected");
+      expect(yield* Ref.get(harness.sessionCount)).toBe(1);
+      expect(yield* Ref.get(harness.releaseCount)).toBe(0);
+    }).pipe(Effect.provide(TestClock.layer())),
+  );
+
   it.effect("quickly times out a stalled mobile foreground liveness probe", () =>
     Effect.gen(function* () {
       const harness = yield* makeHarness({
```

## packages/client-runtime/src/connection/supervisor.ts

Status: modified; +32; −7

```diff
@@ -33,6 +33,7 @@
 const CONNECTION_ESTABLISHMENT_TIMEOUT = "15 seconds";
 const CONNECTION_PROBE_TIMEOUT = "15 seconds";
 const MOBILE_CONNECTION_PROBE_TIMEOUT = "3 seconds";
+const FOREGROUND_PROBE_TIMEOUTS_BEFORE_RECONNECT = 2;
 const BACKOFF_RESET_AFTER_MS = 30_000;
 
 interface SupervisorIntent {
@@ -392,6 +393,7 @@
   const monitorConnectedLease = Effect.fnUntraced(function* (
     lease: ConnectionDriver.EnvironmentConnectionLease,
   ) {
+    let foregroundProbeTimeoutCount = 0;
     for (;;) {
       const next = yield* Queue.take(signals);
       switch (next._tag) {
@@ -415,19 +417,23 @@
             return true;
           }
           if (next.reason === "application-active" || next.reason === "application-active-probe") {
+            const tolerateProbeTimeout = next.reason === "application-active";
             const probe = yield* lease.session.probe.pipe(
+              Effect.as(true),
               Effect.timeoutOrElse({
                 duration:
                   next.reason === "application-active-probe"
                     ? MOBILE_CONNECTION_PROBE_TIMEOUT
                     : CONNECTION_PROBE_TIMEOUT,
                 orElse: () =>
-                  Effect.fail(
-                    new ConnectionTransientError({
-                      reason: "timeout",
-                      detail: `${target.label} did not respond to a connection health check.`,
-                    }),
-                  ),
+                  tolerateProbeTimeout
+                    ? Effect.succeed(false)
+                    : Effect.fail(
+                        new ConnectionTransientError({
+                          reason: "timeout",
+                          detail: `${target.label} did not respond to a connection health check.`,
+                        }),
+                      ),
               }),
               Effect.forkChild,
             );
@@ -441,7 +447,26 @@
                 ),
               );
               if (probeEvent._tag === "ProbeCompleted") {
+                const responded = yield* probeEvent.exit;
+                if (responded) {
+                  foregroundProbeTimeoutCount = 0;
+                  break;
+                }
+                foregroundProbeTimeoutCount += 1;
+                if (foregroundProbeTimeoutCount >= FOREGROUND_PROBE_TIMEOUTS_BEFORE_RECONNECT) {
+                  return yield* new ConnectionTransientError({
+                    reason: "timeout",
+                    detail: `${target.label} did not respond to a connection health check.`,
+                  });
+                }
+                yield* Effect.logWarning(
+                  "Foreground connection health check timed out; keeping the existing session.",
+                ).pipe(
+                  Effect.annotateLogs({
+                    "environment.id": target.environmentId,
-                yield* probeEvent.exit;
+                    "environment.label": target.label,
+                  }),
+                );
                 break;
               }
               switch (probeEvent.signal._tag) {
```
