Pub/sub emulator not working with functions-framework

824 Views Asked by At

I have two Cloud Functions:

  1. HTTP triggered function that gets data and publishes to a pub/sub topic called 'reports'
  2. Pub/sub triggered function that consumes the data that was published

It all works fine if i deploy both functions and run in production but I want to run these locally for development but I cant get it all running together in my dev environment.

I have started the emulator gcloud beta emulators pubsub start --project=abc --host-port='localhost:8043'

I created a topic curl -s -X PUT 'http://localhost:8043/v1/projects/abc/topics/reports'

I created a subscription

curl -s -X PUT 'http://localhost:8043/v1/projects/abc/subscriptions/mysub' \
    -H 'Content-Type: application/json' \
    --data '{"topic":"projects/abc/topics/reports","pushConfig":{"pushEndpoint":"http://localhost:8080/projects/abc/topics/reports"}}'

I then tested the endpoint

curl -s -X POST 'http://localhost:8043/v1/projects/abc/topics/reports:publish' \
    -H 'Content-Type: application/json' \
    --data '{"messages":[{"data":"eyJmb28iOiJiYXIifQ=="}]}'
{
  "messageIds": ["1"]
}

All works fine.

I then have function number 1 that should publish:

const { PubSub } = require('@google-cloud/pubsub');
const pubSubClient = new PubSub();

exports.sendReports = async (req, res) => {
  const reports = await getReports(); //Gets reports from database
  const publishMessages = await publishAllMessages(reports);//Publishes each report to the topic
  if (publishReports.length) {
    console.log('reports published');
    res.status(200).send();
  } else {
    console.error(new Error('reports was not published'));
    res.status(400).send();
  }
};

async function publishAllMessages(reports) {
  try {
    const results = reports.map(report => {
      const publish = await publishMessage(JSON.stringify(report));
      console.log(`${report.title} published = ${publish}`);
      return report;
    });
  } catch (err) {
    console.error(err);
    return [];
  }
}

async function publishMessage(data) {
  try {
    const dataBuffer = Buffer.from(data);
    const messageId = await pubSubClient.topic(TOPIC).publish(dataBuffer);
    console.log(`Message ${messageId} published.`);
    return { name: data.title, published: true };
  } catch (err) {
    console.error(err);
    return { name: data.title, published: false };
  }
}

The application is sending the messages but they are not being received by pub/sub. Here is the error:

Error: 5 NOT_FOUND: Resource not found (resource=reports).
    at Object.callErrorFromStatus (/node_modules/@grpc/grpc-js/build/src/call.js:31:26)
    at Object.onReceiveStatus (/sendReports/node_modules/@grpc/grpc-js/build/src/client.js:189:52)
    at Object.onReceiveStatus (/sendReports/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:365:141)
    at Object.onReceiveStatus (/sendReports/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:328:181)
    at /sendReports/node_modules/@grpc/grpc-js/build/src/call-stream.js:187:78
    at processTicksAndRejections (node:internal/process/task_queues:78:11) {
  code: 5,
  details: 'Resource not found (resource=reports).',
  metadata: Metadata { internalRepr: Map(0) {}, options: {} },
  note: 'Exception occurred in retry method that was not classified as transient'
}
1

There are 1 best solutions below

0
On

So I have managed to get it to work.

I started the emulator with: gcloud beta emulators pubsub start --project=abc --host-port='localhost:8043'

Set the environment variables with: gcloud beta emulators pubsub env-init

Create the topic: curl -s -X PUT 'http://localhost:8043/v1/projects/abc/topics/unsent_reports'

Create the subscription:

curl -s -X PUT 'http://localhost:8043/v1/projects/abc/subscriptions/unsent_reports' \
    -H 'Content-Type: application/json' \
    --data '{"topic":"projects/abc/topics/unsent_reports","pushConfig":{"pushEndpoint":"http://localhost:8080/projects/abc/topics/unsent_reports"}}'

and then call the emulator but remember to base64 encode the json data:

curl -s -X POST 'http://localhost:8043/v1/projects/abc/topics/unsent_reports:publish' -H 'Content-Type: application/json' --data '{"messages":[{"data": "base64EncodedData"}]}'