-
Notifications
You must be signed in to change notification settings - Fork 221
Implement V1 compat API for PubSub #1782
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
base: master
Are you sure you want to change the base?
Implement V1 compat API for PubSub #1782
Conversation
Summary of ChangesHello @shettyvarun268, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a significant enhancement to the v2 Pub/Sub CloudEvent handling by integrating v1-compatible argument accessors. The primary goal is to facilitate a seamless migration for developers transitioning their existing v1 Cloud Functions to the v2 signature. By providing direct property access to Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
|
/gemini review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces a v1-compatibility layer for v2 Pub/Sub functions by adding a lazily-computed context property to the CloudEvent object. The implementation is well-structured, using Object.defineProperty for lazy evaluation and providing fallbacks for constructing the resource name. I've identified a bug in the resource name construction for a fallback case and a couple of areas for improvement in the tests to make them more robust and accurate. My feedback includes a high-severity fix for the resource name format and medium-severity suggestions to improve test coverage and correctness.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
The pull request successfully implements V1-compatible API for PubSub events in V2 Cloud Functions, which will greatly assist in migrating existing business logic. The changes introduce "context" and "message" getters to the CloudEvent<MessagePublishedData> class, along with robust helper functions attachPubSubContext and getResourceName to construct the V1 EventContext. The new test cases thoroughly cover the functionality, including handling existing contexts and fallback mechanisms for resource name extraction.
|
|
||
|
|
||
| it("should use 'unknown-project' as fallback for resource name", async () => { | ||
| delete process.env.GCLOUD_PROJECT; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I think we should keep this. In case we receive a malformed event where the EventID is not parsed, this would ensure that the function does not crash. Also considering GCLOUD_PROJECT is an environmental variable, there could be a case when its not populated (?). What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
anything could happen, but it would be extremely rare. My general thinking here is that if we aren't aware of any condition/scenarios where this could happen, then we may choose to fail explicilty and early instead of letting the unknown condition seem like it's working as intended.
Also - i'm not sure if GCLOUD_PROJECT env var is actually used in our logic? Isn't project id extracted from the data included in the cloud event payload?
| data, | ||
| }; | ||
|
|
||
| type PubSubCloudEvent = CloudEvent<pubsub.MessagePublishedData> & { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is pretty uncommon to define a type outside of top-level. I'd suggest just inlining this.
(adding on, there's an argument on whether this specific typing is helpful or not! For testing code, i'd not concern too much with narrowly typing things out)
e.g. message: pubsub.Message<{ hello: "world" }>; could just be message: pubsub.Message; without a lot of loss of type info.
|
|
||
|
|
||
| it("should use 'unknown-project' as fallback for resource name", async () => { | ||
| delete process.env.GCLOUD_PROJECT; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
anything could happen, but it would be extremely rare. My general thinking here is that if we aren't aware of any condition/scenarios where this could happen, then we may choose to fail explicilty and early instead of letting the unknown condition seem like it's working as intended.
Also - i'm not sure if GCLOUD_PROJECT env var is actually used in our logic? Isn't project id extracted from the data included in the cloud event payload?
| * @param event - The event to add the context to. | ||
| * @param topic - The topic the event is for. | ||
| */ | ||
| function addV1Compatibility<T>(event: CloudEvent<MessagePublishedData<T>>, topic: string) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit* I think I'd prefer name like addV1CompatProperties to be more explicit
| Object.defineProperty(event, "message", { | ||
| get: () => (event.data as MessagePublishedData<T>).message, | ||
| }); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you make sure that the type of event.message is properly typed when using it?
| function getResourceName(event: CloudEvent<MessagePublishedData<any>>, topic: string) { | ||
| const match = event.source?.match(/projects\/([^/]+)\/topics\/([^/]+)/); | ||
| const project = match?.[1]; | ||
| const topicName = match?.[2] ?? topic; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit* this is usally called ID not name
(name refers to fulll resource name)
|
|
||
| /** V1- compatible context of this event. | ||
| * | ||
| * This getter is added at runtime for V1 compatibility. | ||
| * May be undefined if not set by a provider | ||
| */ | ||
| readonly context?: EventContext; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather not make this change
Instead in v2/providers/pubsub.ts, consider defining a new type like this:
type PubSubEvent = CloudEvent<MessagePublishedData<T>> &
{
context: ...
message: ...
}
That way, we don't make context property optional as well as be able to incrementally add support for compat properties to each provider
This PR adds the v1-compatible argument getters (context and message) directly to the v2 Pub/Sub CloudEvent class.
This allows developers to access v1-style arguments via property access, e.g., const { message, context } = event;, for a smoother migration of existing business logic to the v2 function signature.Implementation Details
The v1-compatible context getter is implemented as a lazily-computed property on the CloudEvent object. To correctly construct the v1 EventContext from the v2 event's properties, the following two internal helper functions are introduced:
attachPubSubContext<T>(event: CloudEvent<MessagePublishedData<T>>, topic: string):Adds the v1-style context property to the v2 event object using Object.defineProperty.
The getter computes the EventContext by mapping v2 properties (event.id, event.time) and by calling getResourceName.
This ensures the context is only computed once upon first access.
getResourceName(event: CloudEvent<MessagePublishedData<any>>, topic: string):Extracts the full resource name for the v1 EventContext resource object.
It attempts to parse the project ID and topic name from event.source or falls back to environment variables and the function's topic name parameter if necessary.
This is the first of a series of PRs aimed at simplifying the migration from v1 to v2. By introducing this new
onMessagePublished function, we are providing a more robust and flexible way to handle Pub/Sub events in Cloud Functions for Firebase v2.