Multi-origin routing based on header value

I’m working on a project that will stand up multiple pods of compute resources in our AWS environment and will begin to spread our customer load across those pods. Each pod is fronted by AWS ALBs backed by containerized services.

What I’m trying to accomplish with workers is to enable the mutli-pod routing in a worker based on a specific header that we’ll be setting in our customer premise deployed software.

The flow will be as follows:

  • Software connects to the current domain: agent.mydomain.com
  • If the header “multi-pod-routing” is present, but has no value, send the connection along to the currently configured origin (no real change in proxying behavior)
  • If the header is not present, send the connection to the currently configured origin
  • My services will then do some work and tell the software what it’s value for the “multi-pod-routing” header should be
  • The software will then make another connection to agent.mydomain.com with “multi-pod-routing: 12345-abcdef-67890-ghijk”
  • I’ll have a map in a KV store of origin to header value
    ** 12345-abcdef-67890-ghijk:origin2.mydomain.com
    ** 54321-fedcba-09876-kjihg:origin3.mydomain.com
  • Get the origin for the given value and then send the connection to the proper origin

I think I have a handle on checking the header and value and how to create a KV namespace, populate it, and read from the KV namespace, but what I’m not grasping (yet, I’m new) is how to send the connections to the origins properly. I don’t want to redirect because I don’t want the name in the connection to change (software is always connecting to agent.mydomain.com), I want to continue having the connection proxied through CF. Is this possible with workers? Thanks in advance for all pointers or advice.

Take a look at this article:

2 Likes

Great, thanks, that was very helpful. So the url.hostname action is what sends the connection to the origin specified, which can be from variables in the script, or from the KV store (I presume).

Does protocol matter at all for this or for my route in the app? Right now these connections are HTTPS and WSS (secure websockets), and I need to continue to support both. From what I’ve read websockets should “just work” but knowing that for sure would be helpful.

It sounds like there aren’t any roadblocks to do what I need to do. Anything I’m missing?

Thanks

One other question related to this app. I’m using wrangler and environments to develop, build, and deploy the app to my staging and production environments. Each environment will have a separate KV namespace. Is it possible to get the environment where the app is running in the app?

Thanks!

I think I answered my own question on the KV namespaces. I can create multiple namespaces with the same name and associate them with my different environments and accessing them from the code will use the correct one based on the ID in the environment config. Testing time.

I’ve created the KV namespaces and written the app and published it to my staging domain, but I’m not sure if I got everything right. I’m new to workers and I’m not super familiar with javascript. Here’s the code, I’m hoping that someone might be able to take a look? Any help is appreciated, thanks!

Couple edits to the code as I’ve been doing my own review and testing.

addEventListener('fetch', event => {
    event.respondWith(handleRequest(event.request));
    event.passThroughOnException();
});

async function handleRequest(request) {
    const siteId = request.headers.get('multi-prod-routing');
    const fallBackHost = request.headers.get('Host');

    let url = new URL(request.url);

    // if the routing header is empty send along to the default backend origin
    let dest = (!siteId || (siteId && siteId.length === 0)) ?
        await MY_KV.get("default") : await MY_KV.get("siteId");

    // the lookup from the KV failed. send it to the default backend to generate an error.
    url.hostname = dest === null ? fallBackHost : dest;
    return new Response(url, new Request(request));
}