I have two Cloud Functions:
- HTTP triggered function that gets data and publishes to a pub/sub topic called 'reports'
- 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'
}
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:
and then call the emulator but remember to base64 encode the json data: