Skip to content

Commit

Permalink
fix: restart the dev proxy server whenever it closes (#317)
Browse files Browse the repository at this point in the history
When we run `wrangler dev`, the session that we setup with the preview endpoint doesn't last forever, it dies after ignoring it for 5-15 minutes or so. The fix for this is to simply reconnect the server. So we use a state hook as a sigil, and add it to the dependency array of the effect that sets up the server, and simply change it every time the server closes.

Fixes #197

(In wrangler1, we used to restart the whole process, including uploading the worker again, making a new preview token, and so on. It looks like that they may not have been necesssary.)
  • Loading branch information
threepointone authored Jan 27, 2022
1 parent d0bad35 commit d6ef61a
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 4 deletions.
11 changes: 11 additions & 0 deletions .changeset/quick-colts-smash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"wrangler": patch
---

fix: restart the `dev` proxy server whenever it closes

When we run `wrangler dev`, the session that we setup with the preview endpoint doesn't last forever, it dies after ignoring it for 5-15 minutes or so. The fix for this is to simply reconnect the server. So we use a state hook as a sigil, and add it to the dependency array of the effect that sets up the server, and simply change it every time the server closes.

Fixes https://github.com/cloudflare/wrangler2/issues/197

(In wrangler1, we used to restart the whole process, including uploading the worker again, making a new preview token, and so on. It looks like that they may not have been necessary.)
7 changes: 6 additions & 1 deletion packages/wrangler/src/inspect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -315,9 +315,14 @@ export default function useInspector(props: InspectorProps) {
};
}, [
props.inspectorUrl,
retryRemoteWebSocketConnectionSigil,
props.logToTerminal,
wsServer,
// We use a state value as a sigil to trigger a retry of the
// remote websocket connection. It's not used inside the effect,
// so react-hooks/exhaustive-deps doesn't complain if it's not
// included in the dependency array. But its presence is critical,
// so do NOT remove it from the dependency list.
retryRemoteWebSocketConnectionSigil,
]);

/**
Expand Down
32 changes: 29 additions & 3 deletions packages/wrangler/src/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import type {
import WebSocket from "faye-websocket";
import serveStatic from "serve-static";
import type { CfPreviewToken } from "./api/preview";
import { useEffect, useRef } from "react";
import { useEffect, useRef, useState } from "react";

/**
* `usePreviewServer` is a React hook that creates a local development
Expand Down Expand Up @@ -80,6 +80,17 @@ export function usePreviewServer({
{ request: IncomingMessage; response: ServerResponse }[]
>([]);

/**
* The session doesn't last forever, and will evetually drop
* (usually within 5-15 minutes). When that happens, we simply
* restart the effect, effectively restarting the server. We use
* a state sigil as an effect dependency to do so.
*/
const [retryServerSetupSigil, setRetryServerSetupSigil] = useState<number>(0);
function retryServerSetup() {
setRetryServerSetupSigil((x) => x + 1);
}

useEffect(() => {
// If we don't have a token, that means either we're just starting up,
// or we're refreshing the token.
Expand Down Expand Up @@ -119,6 +130,11 @@ export function usePreviewServer({
const remote = connect(`https://${previewToken.host}`);
cleanupListeners.push(() => remote.destroy());

// As mentioned above, the session may die at any point,
// so we need to restart the effect.
remote.on("close", retryServerSetup);
cleanupListeners.push(() => remote.off("close", retryServerSetup));

/** HTTP/2 -> HTTP/2 */
const handleStream = createStreamHandler(previewToken, remote, port);
proxy.on("stream", handleStream);
Expand Down Expand Up @@ -209,9 +225,19 @@ export function usePreviewServer({
cleanupListeners.push(() => proxy.off("upgrade", handleUpgrade));

return () => {
cleanupListeners.forEach((d) => d());
cleanupListeners.forEach((cleanup) => cleanup());
};
}, [previewToken, publicRoot, port, proxy]);
}, [
previewToken,
publicRoot,
port,
proxy,
// We use a state value as a sigil to trigger reconnecting the server.
// It's not used inside the effect, so react-hooks/exhaustive-deps
// doesn't complain if it's not included in the dependency array.
// But its presence is critical, so Do NOT remove it from the dependency list.
retryServerSetupSigil,
]);

// Start/stop the server whenever the
// containing component is mounted/unmounted.
Expand Down

0 comments on commit d6ef61a

Please sign in to comment.