-
Notifications
You must be signed in to change notification settings - Fork 158
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
Cloud events incorrectly unmarshalled: first argument is undefined, 2nd argument differs from production #41
Comments
From looking through the code, my problem is fixed if isBinaryCloudEvent() in wrapEventFunction always returned true at line 433. Currently the push notification from the pubsub emulator is causing the code to enter the else clause that supports legacy events and CloudEvents in structured content mode. I'm not sure if this is an issue with the pubsub emulator, or if the support for legacy events can be removed, otherwise I'd be happy to push a CL for review. |
Maybe this needs to be a separate issue, but I am running into something similar with pubsub triggered functions. In GCF, I have a pubsub triggered function that receives these as it's arguments from an event on the pubsub topic:
argument2
Locally, I am trying to test this function with this setup:
This results in argument 1 being
After some debugging, |
I'm seeing a simular issue when following the instructions on forwarding from the PubSub emulator to a function described here. i'm running the functions emulator as follows
this is how i'm forwarding topics
my function target just looks like
the output I get after publishing to one of the forwarded topics is as follows
|
There is a mismatch between what's currently in the Google Cloud Functions docs for pubsub invocations and what happens when running If you don't specify a context prop in your request body when invoking the function via HTTP e.g. You can see why here https://github.com/GoogleCloudPlatform/functions-framework-nodejs/blob/master/src/invoker.ts#L446 . I don't really understand what the author is getting at with the comments in that block but, at least now the first argument will be defined if we supply a context. However, there is still a problem because GCF will be invoked from pubsub with a data prop on the event. From the docs:
Unfortunately, instead of passing the event itself the invoker is passing just the data prop. https://github.com/GoogleCloudPlatform/functions-framework-nodejs/blob/master/src/invoker.ts#L457 Can any of the contributors here comment on reasoning behind working towards the cloud events spec vs the google runtime, especially considering this repo is housed in GCP? |
Read more into the knative cloud events spec. The go receiver signature https://knative.dev/docs/eventing/samples/helloworld/helloworld-go/ Is there any reason not to simply change https://github.com/GoogleCloudPlatform/functions-framework-nodejs/blob/master/src/invoker.ts#L457 to
UPDATE: Forked the repo and the tests explain a bit about the intentions. I also read the Cloud Functions Node docs more. After all that, the shortest path to replicating the pubsub signature is just to change your invocation to this: UPDATE TO UPDATE:
Hope my struggle here helps someone else out, I will say though that making PubSub more prevalent on the docs would have saved me (and perhaps many others that aren't yet familiar with the cloudevent spec) a solid hour 😅 |
@comolongo @stephenhandley Did you find a solution for this? |
Using requestbin.com I saw that the PubSub Emulator behaves just like GCP PubSub (production). I also noticed, by looking at the headers and json data, that GCP PubSub does not send CloudEvents (binary nor structured). And by looking at the code + comments in invoker.ts, I noticed that Cloud Functions Framework only support CloudEvents (binary and structured). So this means unfortunately that Cloud Functions Framework is currently not compatible with GCP PubSub. It should be fairly easy to fix the code so that it handles GCP PubSub events properly by checking the json data schema/structure. I provided the requests from both GCP PubSub and PubSub Emulator. I also provided a snippet of the source code where the problem is. Push request from PubSub EmulatorAccept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Content-Type: application/json
User-Agent: Java/1.8.0_172
... {
"subscription": "projects/my-project/subscriptions/my-sub-1",
"message": {
"data": "eyJ0aW1lc3RhbXAiOiIyMDIwLTAyLTE0VDE2OjMxOjMxLjU3NVoiLCJ1c2VySWQiOiJ1c2VyLTAwNyJ9",
"messageId": "6",
"attributes": {
"myCustomId": "ce02c4b1-3536-408f-b6fe-b0db29a5928b"
}
}
} Push request from GCP PubSub (production)Accept: application/json
Accept-Encoding: gzip,deflate,br
Content-Type: application/json
From: noreply@google.com
User-Agent: APIs-Google; (+https://developers.google.com/webmasters/APIs-Google.html)
... {
"message": {
"attributes": {
"myCustomId": "9ad2e7c8-3cfa-4872-a658-4e67cfad7a85"
},
"data": "eyJ0aW1lc3RhbXAiOiIyMDIwLTAyLTE0VDE4OjQ0OjI4LjE2OFoiLCJ1c2VySWQiOiJ1c2VyLTAwNyJ9",
"messageId": "801978309740373",
"message_id": "801978309740373",
"publishTime": "2020-02-14T18:44:30.209Z",
"publish_time": "2020-02-14T18:44:30.209Z"
},
"subscription": "projects/my-project/subscriptions/my-sub-2"
} Location of problem in the source codefunctions-framework-nodejs/src/invoker.ts Lines 431 to 447 in fc63000
Question about the comments: What does "legacy events" mean in this context? Is it legacy version of CloudEvents or is the author referring to GCP PubSub events? Ping @swalkowski |
I, too, am struggling with the apparently simple scenario of using functions-framework to host a local background function that acts as a push endpoint for a Cloud PubSub topic. As reported by others here, my function receives an I have a one line change to invoker.js that makes things work in my particular case (see below), but I'm not sure if it's general purpose or if it breaks other things. The documentation for Cloud Pub/Sub gives an example HTTP request format of:
This matches what I see, and what @alexsanzdev reported above. Furthermore, the sample code for a background function is given as:
But when we look at the code in invoker.js, it assumes that the incoming HTTP request will always have a payload at req.body.data. As seen above, the payload for these PubSub messages is actually at req.body.message.
So to make things work, I can change invoker.js such that it sets
Of course, I don't know what else that would break. I'm having a hard time understanding how For completeness, my test script is like: $ gcloud beta emulators pubsub start --host-port=localhost:9099 where createSubscription.js is like:
I'm happy to make a PR for the "fix", but I suspect there's more to the story and would appreciate guidance. |
@mykwillis yeah, I asked my self exact the same question. Is CF framework really used in runtime on GCP production? Because the behavior is different. Or is it depending on whether you have CF framework dependency as production or dev (in package.json). @mykwillis your fix is nice and simple, and looks more like the missing line than a fix. Maybe it should have been there from the start. According to the comments this if statement branch is for "legacy events and CloudEvents in structured content mode". But what is a legacy event? Is it the event message current production pubsub sends? I yes, then this is the right if branch to put your fix. But if legacy event means something else, then maybe this is not the proper if branch. Did you run the tests? |
@alexsanzdev the tests pass, but I don't believe that they are terribly comprehensive. There is no test data that looks anything like the Cloud Pub/Sub request. Incidentally, there is test data named "GCF legacy event" that looks like this:
So it seems like maybe there should be a test for the PubSub event format, and the associated fix to pull data from correct place, but I'm still stuck scratching my head asking how this works on GCF production. In any case, this whole section seems to be flat wrong, because following the approach simply doesn't work. |
To contribute: I'm on Mac Os Catalina 10.15.4 I have Google Pub/Sub Emulator up and running:
I have Google Cloud Function Framework up and running:
Pub/Sub has a Project created. All good! I'm able to publish a Message to the existing Topic and the Subscription pushes to the Google Cloud Function Framework on the According to the documentation and for testing purposes:
According to the documentation and for testing purposes:
Problem n1:
So at the end, out of the box the code doesn't work.
Problem n2:
This time
And
Again, the original version of On this page:
And it doesn't work. J. |
Hey all, thanks for the comments. I know this is an issue. I'm not sure of the exact solution right now. We're formally supporting CloudEvents in the Functions Framework spec and will be looking at better, more accurate support for CloudEvents (and legacy events) in the frameworks. I've pinged a colleague to see if we can also improve our docs on cloud.google.com
I've removed that section until we have accurate docs. |
If someone (like me) doesn't care for CloudEvents which require to build big JSON-s plus add custom headers to the request to test simple things, and which are additionally not compatible with current GCP PubSub, can use the following format instead of this described in docs. In GCP if I send the The event is: {
"a": 2
} Context is: {
"eventId": "450000223",
"resource": {
"service": "pubsub.googleapis.com",
"name": "projects/xxx/topics/yyy"
},
"eventType": "google.pubsub.topic.publish",
"timestamp": "2020-06-03T13:20:06.789Z"
} The same can be achieved with the following request to functions-framework endpoint: {
"data": {
"a": 2
},
"context": {
"eventId": "450000223",
"resource": {
"service": "pubsub.googleapis.com",
"name": "projects/xxx/topics/yyy"
},
"eventType": "google.pubsub.topic.publish",
"timestamp": "2020-06-03T13:20:06.789Z"
}
} Or even if you don't care about the context: {
"data": {
"a": 2
}
} In my opinion this format should be included in docs before CloudEvents format description. |
This still seems to be a problem. I'm not a JS dev and I'm concerned that I don't really understand what else functions-framework is trying to support but... If we assume that when the request contains
|
When Pubsub notifications are sent to a locally hosted cloud event function, the first argument is undefined. It should contain the event information. The 2nd argument though present, does not match production signature; rather than containing metadata about the notification, it contains the entire event object, which should be the contents of argument 1 instead.
My dummy cloud events function:
Pub/sub notification being sent:
helloEvents log in production:
Argument 1, data, is:
Argument 2, context, is:
On local, the results I get is very different.
The text was updated successfully, but these errors were encountered: