Search code examples
firebasemod-rewritefirebase-hostinggoogle-cloud-runsveltekit

cloud run api service response broken when I use firebase rewrites


The firebase Sveltekit client app and server api use a google cloud run hosting container. This works fine when I use the cloud run url: https://app...-4ysldefc4nq-uc.a.run.app/

But when I use firebase rewriting the client works fine using: https://vc-ticker.web.app/... but receives 502 and 504 responses from the API service. The cloud run log does not show any errors, receives the client fetch POST request and returns a Readablestream response.
But this API service response stream never arrives when using rewrites.

firebase.json

{
  "hosting": {
    "public": "public",   !! NOT used, cloud run hosts the app
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "**",
        "run": {
          "serviceId": "vc-ticker-app",
          "region": "us-central1"
        }
      }
    ]
  }
}

+page.svelte client API request:

const logging = true;
const controller = new AbortController();
let reader = null;
const signal = controller.signal;

async function streamer(params) {
  console.log("stream with logging:", logging, JSON.stringify(params));
  try {
    const response = await fetch("api/my-ticker", {
      method: "POST",
      body: JSON.stringify(params),
      headers: {
        "content-type": "application/json",
      },
      signal: signal,
    });

    const stream = response.body.pipeThrough(new TextDecoderStream("utf-8"));
    reader = stream.getReader();

    while (true) {
      const { value, done } = await reader.read();

      if (done || response.status !== 200) {
        console.log("done response", response.status, done, value);
        await reader.cancel(`reader done or invalid response: ${response.status}`);
        reader = null;
        break;
      }

      // response ok: parse multi json chunks => array => set store
      const quotes = {};
      JSON.parse(`[${value.replaceAll("}{", "},{")}]`).forEach((each, idx) => {
        quotes[each.id] = [each.price, each.changePercent];
        console.log(`quote-${idx}:`, quotes[each.id]);
      });
      positions.set(quotes);
    }
  } catch (err) {
    console.log("streamer exception", err.name, err);
    if (reader) {
      await reader.cancel(`client exception: ${err.name}`);
      reader = null;
    }
  }
}

$: if ($portfolio?.coins) {
  const params = {
    logging,
    symbols: Object.values($portfolio.symbols),
  };
  streamer(params);
}

onDestroy(async () => {
  if (reader) await reader.cancel("client destroyed");
  controller.abort();
  console.log("finished");
});

I use the Sveltekit adapter-node to build the app.


Solution

  • From firebase support:

    I got an answer from the engineering team. Unfortunately Firebase Hosting does not support streaming responses at the moment. I’ve created a feature request so they will consider implementing it.

    Please be informed that submitting a feature request doesn’t guarantee that it will be implemented. Keep an eye on the release notes.

    I realize that this is not the answer you expected from me, but unfortunately there is nothing I can do about it.