Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support streaming streaming responses for callable functions. #8609

Open
wants to merge 30 commits into
base: main
Choose a base branch
from

Conversation

taeold
Copy link

@taeold taeold commented Oct 25, 2024

The new .stream() API allows the client to consume streaming responses from the WIP streaming callable functions in Firebase Functions Node.js SDK.

When client makes a request to the callable function w/ header Accept: text/event-stream, the callable function responds with response chunks in Server-Sent Event format.

The sdk changes here abstracts over the wire-protocol by parsing the response chunks and returning an instance of a AsyncIterable to consume to data:

import { getFunctions, httpsCallable } from "firebase/functions";

const functions = getFunctions();
const generateText = httpsCallable(functions, 'generateText');
const resp = await generateText.stream(
  { text: 'What is your favorite Firebase service and why?' },
  { signal: AbortSignal.timeout(60_000) },
);
try {
  for await (const message of resp.stream) {
     console.log(message); // prints "foo", "bar"
  }
  console.log(await resp.data) // prints "foo bar"
} catch (e) {
  // FirebaseError(code='cancelled', message='Request was cancelled.');
  console.error(e)
}

Copy link

changeset-bot bot commented Oct 25, 2024

🦋 Changeset detected

Latest commit: b9a42e5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@firebase/functions Minor
firebase Minor
@firebase/functions-compat Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@google-oss-bot
Copy link
Contributor

google-oss-bot commented Oct 25, 2024

Size Report 1

Affected Products

  • @firebase/functions

    TypeBase (ffbf5a6)Merge (a2c6b1b)Diff
    browser9.72 kB13.7 kB+3.95 kB (+40.7%)
    main10.3 kB14.2 kB+3.95 kB (+38.4%)
    module9.72 kB13.7 kB+3.95 kB (+40.7%)
  • bundle

    TypeBase (ffbf5a6)Merge (a2c6b1b)Diff
    functions (call)32.0 kB34.4 kB+2.36 kB (+7.4%)
  • firebase

    TypeBase (ffbf5a6)Merge (a2c6b1b)Diff
    firebase-compat.js794 kB797 kB+2.23 kB (+0.3%)
    firebase-functions-compat.js8.21 kB10.4 kB+2.20 kB (+26.8%)
    firebase-functions.js12.0 kB14.6 kB+2.58 kB (+21.5%)

Test Logs

  1. https://storage.googleapis.com/firebase-sdk-metric-reports/8gqRUfJIsW.html

@google-oss-bot
Copy link
Contributor

google-oss-bot commented Oct 25, 2024

Size Analysis Report 1

Affected Products

  • @firebase/functions

    • FunctionsError

      Size

      TypeBase (ffbf5a6)Merge (a2c6b1b)Diff
      size2.48 kB2.52 kB+41 B (+1.7%)
      size-with-ext-deps20.3 kB20.3 kB+41 B (+0.2%)
    • connectFunctionsEmulator

      Size

      TypeBase (ffbf5a6)Merge (a2c6b1b)Diff
      size2.46 kB2.50 kB+41 B (+1.7%)
      size-with-ext-deps20.3 kB20.4 kB+41 B (+0.2%)
    • getFunctions

      Size

      TypeBase (ffbf5a6)Merge (a2c6b1b)Diff
      size2.64 kB2.68 kB+41 B (+1.6%)
      size-with-ext-deps28.1 kB28.2 kB+41 B (+0.1%)
    • httpsCallable

      Size

      TypeBase (ffbf5a6)Merge (a2c6b1b)Diff
      size6.12 kB8.45 kB+2.33 kB (+38.1%)
      size-with-ext-deps24.0 kB26.4 kB+2.36 kB (+9.8%)

      Dependency

      TypeBase (ffbf5a6)Merge (a2c6b1b)Diff
      functions

      12 dependencies

      _errorForResponse
      call
      callAtURL
      codeForHTTPStatus
      decode
      encode
      failAfter
      httpsCallable
      httpsCallable$1
      mapValues
      postJSON
      registerFunctions

      16 dependencies

      _errorForResponse
      call
      callAtURL
      codeForHTTPStatus
      createResponseStream
      decode
      encode
      failAfter
      httpsCallable
      httpsCallable$1
      makeAuthHeaders
      mapValues
      postJSON
      registerFunctions
      stream
      streamAtURL

      + createResponseStream
      + makeAuthHeaders
      + stream
      + streamAtURL

      variables

      APP_CHECK_INTERNAL_NAME
      AUTH_INTERNAL_NAME
      DEFAULT_REGION
      FUNCTIONS_TYPE
      LONG_TYPE
      MESSAGING_INTERNAL_NAME
      UNSIGNED_LONG_TYPE
      errorCodeMap
      name
      version

      11 dependencies

      APP_CHECK_INTERNAL_NAME
      AUTH_INTERNAL_NAME
      DEFAULT_REGION
      FUNCTIONS_TYPE
      LONG_TYPE
      MESSAGING_INTERNAL_NAME
      UNSIGNED_LONG_TYPE
      errorCodeMap
      name
      responseLineRE
      version

      + responseLineRE

    • httpsCallableFromURL

      Size

      TypeBase (ffbf5a6)Merge (a2c6b1b)Diff
      size6.07 kB8.35 kB+2.28 kB (+37.5%)
      size-with-ext-deps23.9 kB26.2 kB+2.30 kB (+9.6%)

      Dependency

      TypeBase (ffbf5a6)Merge (a2c6b1b)Diff
      functions

      11 dependencies

      _errorForResponse
      callAtURL
      codeForHTTPStatus
      decode
      encode
      failAfter
      httpsCallableFromURL
      httpsCallableFromURL$1
      mapValues
      postJSON
      registerFunctions

      14 dependencies

      _errorForResponse
      callAtURL
      codeForHTTPStatus
      createResponseStream
      decode
      encode
      failAfter
      httpsCallableFromURL
      httpsCallableFromURL$1
      makeAuthHeaders
      mapValues
      postJSON
      registerFunctions
      streamAtURL

      + createResponseStream
      + makeAuthHeaders
      + streamAtURL

      variables

      APP_CHECK_INTERNAL_NAME
      AUTH_INTERNAL_NAME
      DEFAULT_REGION
      FUNCTIONS_TYPE
      LONG_TYPE
      MESSAGING_INTERNAL_NAME
      UNSIGNED_LONG_TYPE
      errorCodeMap
      name
      version

      11 dependencies

      APP_CHECK_INTERNAL_NAME
      AUTH_INTERNAL_NAME
      DEFAULT_REGION
      FUNCTIONS_TYPE
      LONG_TYPE
      MESSAGING_INTERNAL_NAME
      UNSIGNED_LONG_TYPE
      errorCodeMap
      name
      responseLineRE
      version

      + responseLineRE

Test Logs

  1. https://storage.googleapis.com/firebase-sdk-metric-reports/sDELt3rVwd.html

Copy link
Contributor

github-actions bot commented Nov 9, 2024

Changeset File Check ✅

  • No modified packages are missing from the changeset file.
  • No changeset formatting errors detected.

Copy link
Contributor

@hsubox76 hsubox76 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CI stuff that you want to do before you finalize and merge:

(1) To address the formatting CI failure, run yarn format locally.
(2) To address the docgen failure, run yarn docgen:all locally. This will modify some files in docs-devsite which will require a techwriter review approval in addition to a JS core team review. go/firebase-contacts tells me the techwriter assigned to CF3 is Eric Gilmore.

packages/functions-types/index.d.ts Outdated Show resolved Hide resolved
packages/functions/package.json Show resolved Hide resolved
.changeset/bright-scissors-care.md Outdated Show resolved Hide resolved
.changeset/bright-scissors-care.md Show resolved Hide resolved
@taeold taeold marked this pull request as ready for review November 24, 2024 20:04
@taeold taeold requested review from a team as code owners November 24, 2024 20:04
packages/functions/package.json Show resolved Hide resolved
long: 420
});
} catch (err) {
console.error(err);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a chai error, too, I think.

export interface HttpsCallableStreamOptions {
/**
* An AbortSignal that can be used to cancel the streaming response. When the signal is aborted,
* both the underlying connection and stream will be terminated.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe that's true, but I could be wrong. I added some Abort Signals to the Gemini SDK, and in doing that I learned that Abort doesn't close the connection, it just stops listening for network responses at the application level. Therefore the server operation might continue to move forward, the app just wont' be notified of the result.

Does that affect billing or usage concerns?

@@ -244,10 +275,30 @@ async function postJSON(
};
}

async function makeAuthHeaders(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a function description comment block above this?

};
}

function createResponseStream(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A header here, too, please.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants