-
Notifications
You must be signed in to change notification settings - Fork 118
Functions Framework does not work with the Pub/Sub emulator #23
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Comments
Thanks for the report, I'll take a look at this and see what's going on. |
+1 on this. I can confirm I'm seeing the same exact result for the same exact use case. |
It looks like when setting
on the following function def main(event, context):
print(event, context) with the following output
|
I've made fork of this repo, that supports events from Pub/Sub. Not the cleanest/best solution, but it works for my needs. Hope this may help |
I will try the fork!! Thank you a lot I really needed a patch even not the cleanest for this ! |
Thanks for the report and workaround. As Dustin stated, we'll look into this (it may be a similar issue with other frameworks). |
Just a quick update here: we've decided to add support for these legacy-style Pub/Sub events. Hang tight while we roll this out, and thanks for your patience. |
Hi, not sure but I think it's related:
cheers |
@dror-g It looks like your function expects a Pub/Sub message but you're calling it with headers that indicate that it's a binary CloudEvent instead. Try calling it like so:
Where the value of |
Hi @di , yes, like OP I am trying to emulate Pub/Sub triggered function, and we both tried to post a mock.json file. Tried this function:
What works:
What doesn't: mock.json:
|
I had this same issue working with the nodejs pubsub client for cloud functions |
Just so I'm clear, is this an issue with the functions framework, the pubsub emulator, someone's understanding of the correct payload format, or the (adapted) documentation around the technique for connecting the emulator to the functions framework? I'd like to try using the functions framework as part of an end-to-end test with the pubsub emulator but I'm not clear whether this would be a blocking issue. Or, after reading @di 's comment, does this only affect legacy triggers? |
Google's "getting started" documentation describes the Maybe the easiest workaround is to write a wrapper function just for testing that def hello_pubsub_test_wrapper(event_raw, context):
return hello_pubsub(json.loads(event_raw), context)
def hello_pubsub(event: dict, context):
"""Background Cloud Function to be triggered by Pub/Sub.
Args:
event (dict): The dictionary with data specific to this type of
event. The `data` field contains the PubsubMessage message. The
`attributes` field will contain custom attributes if there are any.
context (google.cloud.functions.Context): The Cloud Functions event
metadata. The `event_id` field contains the Pub/Sub message ID. The
`timestamp` field contains the publish time.
"""
import base64
print("""This Function was triggered by messageId {} published at {}
""".format(context.event_id, context.timestamp))
if 'data' in event:
name = base64.b64decode(event['data']).decode('utf-8')
else:
name = 'World'
print('Hello {}!'.format(name)) functions-framework --target=hello_pubsub_test_wrapper --signature-type=event echo -n "test" | base64
=>
dGVzdA== mockPubsub.json: {
"data": "dGVzdA==",
"messageId": "136969346945"
} curl -d @mockPubsub.json -X POST \
-H "Ce-Type: true" \
-H "Ce-Specversion: true" \
-H "Ce-Source: true" \
-H "Ce-Id: true" \
-H "Content-Type: application/json" \
http://localhost:8080 This yields: |
The more I read the google documentation, the more frustrated and confused I get. Am I mistaken or is it full of errors? As far as I can tell from running the example I just posted, the data payload is just a plain old But here it says "When using JSON over REST, message data must be base64-encoded. ", but then nowhere in the examples does it do anything with base64 encoding. And when using the future = publisher.publish(
topic_path, data=data.encode("utf-8") # data must be a bytestring.
) Soooo... this example uses is a sequence of bytes, not a base64-encoded string. Is there something that's base64-encoding them behind the scenes? I have no idea, because there seems to be no single source of truth. Anyway, I removed base64 encoding from that example and it seems to work fine when I deploy it to GCP and send it an un-base64-encoded string: gcloud functions call hello_pubsub --project=my-project --data '{"data": "Not Base64 Encoded"}' The functions-framework seems to pass it along too. I have no idea if I've done any of this correctly or not, but it seems to work. |
I'm also having an issue connecting the emulator to functions-framework. I'm publish a message with data={"foo": "bar"}, and the functions-framework shows the request comes in with the header
And yet when my function is called: def receive_event(event, context=None):
print('receive_event(event={}, context={}'.format(event, context))
print('receive_event event type {}'.format(type(event))) It prints:
Is the posted json above using this legacy format you're referring to? From the snippets pasted in earlier comments on this issue thread, it seems that perhaps I am publishing using an old version of I'm probably going to just fork the functions-framework to make it work in this environment. |
Editing the def _run_legacy_event(function, request):
event_data = request.get_json()
if not event_data:
flask.abort(400)
###############
# Need to add this code to make pubsub events work.
if 'message' in event_data:
if 'data' not in event_data:
message = event_data['message']
event_data['data'] = {
'data': message.get('data'),
'attributes': message.get('attributes')
}
###############
event_object = _Event(**event_data)
data = event_object.data
context = Context(**event_object.context)
function(data, context) |
I can confirm that the bug is still there. If I try to put the following headers on the functions-framework request:
then, I get also the attribute, but it is not a dict (like in the true environment) but it is a serialized-json instead... so without modifying the function framework sources, the only workaround I found is to add the following, and send the curl request with the previous headers:
Totally unusable. I expected better, really better from Google. |
Thanks all @RomikimoR @wojtek-viirtue @isaldana @Uraniun @dror-g @27Bslash6 @mikebridge @jacobg @gabriel-young @lrodorigo for your patience! Functions Frameworks is now working with Pub/Sub Emulator! 🎉 Something like below will work: # Terminal 1
gcloud beta emulators pubsub start --project=abc --host-port=localhost:8080
# Terminal 2
functions-framework --target=hello --debug --port=8082
# Terminal 3
export PUBSUB_PROJECT_ID=abc
$(gcloud beta emulators pubsub env-init)
git clone https://github.com/googleapis/python-pubsub.git
cd samples/snippets/
python publisher.py abc create may
python subscriber.py abc create-push may five http://localhost:8082
python publisher.py abc publish may Thanks again @matthewrobertson. |
Thanks @anguillanneuf for the added documentation about this. However, I'm a bit confused here. The examples you show suppose the Cloud Function expects a def hello(request):
return "Hello world!" However, unless there is something I miss here, the official way of implementing a Pub/Sub Cloud Function tells us to define function with two arguments: def hello_pubsub(event, context):
import base64
print("""This Function was triggered by messageId {} published at {} to {}
""".format(context.event_id, context.timestamp, context.resource["name"]))
if 'data' in event:
name = base64.b64decode(event['data']).decode('utf-8')
else:
name = 'World'
print('Hello {}!'.format(name))) If I try to debug those kind of functions using with the framework and the Pub/Sub emulator, I get this kind of error:
Obviously because we get a So, what is the right way to debug a Pub/Sub Cloud Function? |
@frankie567 Oh no, this issue was closed and I did not see your comment until now! Part of what you describe sounds like a feature request for Functions Frameworks (FF). I opened a new issue #141 and cc'ed you there.
For local testing, the Pub/Sub emulator and FF should suffice if you are okay with using |
Reopening this until we can update the example to use a background function instead of a HTTP function per #141. |
Hello,
I am trying to emulate the behavior of my application.

To do so I use the Pub/Sub Emulator and the Google cloud function emulator.
The cloud function I created looks like the image following and is supposed to be triggered by an event :
Both emulators are communicating without issue.
I followed the example of this repository: https://github.com/GoogleCloudPlatform/functions-framework-nodejs to link them.
When, following the example, I use this command line:
On my Cloud function emulator I do receive this :

So this is exactly what I want.
Yet, I do not want to use the command line to send messages but I want the cloud function to be triggered by a Pub/Sub event.
Here you can see the methods creating:
I. a pull subscription
II. a push subsciption
III. publishing messages
However When I want to publish messages, the Pub/Sub emulator detect the connection:
But then the Cloud Function emulator does not receive the data, although it detects an event occurred:

I think it is probably because POSTING to a Gcloud Function needs some headers with the 'Ce-' prefix.
But searching a bit on how to add headers to my push subscriber I found out this wasn't possible.
It's possible I totally missed something...
I hope this is understandable.
Thank you
The text was updated successfully, but these errors were encountered: