I'd like to schedule the execution of a Cloud Function to a specific time. It should be run only once.
I basically have a function "startTask" which modifies some data in the Firestore database. After X seconds (the time is passed to the startTask function), the "finishTask" function should be called.
I already tried messing around with Google Cloud Tasks but I feel like this isn't the right way to go.
Google Cloud does not have service that will do what you need that I am aware of. If you need X to happen N seconds after user does Y, you will need to code that service yourself.
You do not specify what services you are using for compute (App Engine, Compute Engine, Kubernetes, etc.) but writing a task secheduling service in just about any language is not very hard. There are many ways to accomplish this (client side code / server side code). Many OS / language combinations support scheduling a function with a timeout and callback.
You can use Cloud Tasks. It will allow you to be alerted after x amount of seconds.
https://cloud.google.com/tasks/docs/creating-http-target-tasks
The easiest way is to create a pub/sub topic, cron-topic that your cloud function subscribes to. Cloud Scheduler can push an event to cron-topic on a schedule
Create the Topic & Subscription
gcloud pubsub topics create cron-topic
# create cron-sub for testing. Function will create it's own subscription
gcloud pubsub subscriptions create cron-sub --topic cron-topic
Create the Schedule
Command is below, but since it's beta, see the console guide here
# send a message every 3 hours. For testing use `0/2 * * * *` for every 2 min
gcloud beta scheduler jobs create pubsub --topic=cron-topic --schedule='0 */3 * * *'
Create a Function to Consume the cron-topic Topic
Put your function code in the current directory and use this command to deploy the function listening to the cron-topic topic
FUNCTION_NAME=cron-topic-listener
gcloud functions deploy ${FUNCTION_NAME} --runtime go111 --trigger-topic cron-topic
note pub/sub events are sent at least once. In some cases the event can be sent more than once. Make sure your function is idempotent
Related
When I create a Google Cloud Function, I am offered to set a "Trigger":
and the "Maximum number of instances":
What happens if a Pub/Sub triggered Cloud Function faces periods when it receives more messages than it can instantly process?
Concrete example: I am sending 200 strings to the Cloud Function per minute, for 5 minutes. One instance can process 10 strings in a minute, and the "Maximum number of instances" is 10, so in total, 100 strings per minute is processed. What will happen to the other half of the 200 strings, will they "wait" in the Pub/Sub topic until they are processed, or will these inputs get lost?
What happens if a Pub/Sub triggered Cloud Function faces periods when it receives more messages than it can instantly process?
Initially, this would result to some messages to not process (UNACK will be sent), and will be left behind. However, to be able to work around with this, you just need to enable the retry policy on the function.
Cloud Functions guarantees at-least-once execution of an event-driven function for each event emitted by an event source. However, by default, if a function invocation terminates with an error, the function will not be invoked again, and the event will be dropped. When you enable retries on an event-driven function, Cloud Functions will retry a failed function invocation until it completes successfully, or the retry window (by default, 7 days) expires.
You can enable retries by providing the --retry flag when creating the function via the gcloud command-line tool or checking the "Retry on failure" box when creating via the Cloud Console.
To update the subscription to use a retry policy, find the name of the subscription created by Cloud Functions in the Cloud Console Pub/Sub section or use the gcloud pubsub subscriptions update command with the necessary flags.
The messages/events just queue up in the subscription until they get processed. No need to specify retry behaviour with --retry.
I wish to schedule a Vertex Pipelines and deploy it from my local machine for now.
I have defined my pipeline which runs well I deploy it using: create_run_from_job_spec, on AIPlatformClient running it once.
When trying to schedule it with create_schedule_from_job_spec, I do have a Cloud Scheduler object well created, with a http endpoint to a Cloud Function. But when the scheduler runs, it fails because of Permission denied error. I used several service accounts with owner permissions on the project.
Do you know what could have gone wrong?
Since AIPlatformClient from Kubeflow pipelines raises deprecation warning, I also want to use PipelineJob from google.cloud.aiplatform but I cant see any direct way to schedule the pipeline execution.
I've spent about 3 hours banging my head on this too. In my case, what seemed to fix it was either:
disabling and re-enabling cloud scheduler api. Why did I do this? There is supposed to be a service account called service-[project-number]#gcp-sa-cloudscheduler.iam.gserviceaccount.com. If it is missing then re-enabling API might fix it
for older projects there is an additional step: https://cloud.google.com/scheduler/docs/http-target-auth#add
Simpler explanations include not doing some of the following steps
creating a service account for scheduler job. Grant cloud function invoker during creation
use this service account (see create_schedule_from_job_spec below)
find the (sneaky) cloud function that was created for you it will be called something like 'templated_http_request-v1' and add your service account as a cloud function invoker
response = client.create_schedule_from_job_spec(
job_spec_path=pipeline_spec,
schedule="*/15 * * * *",
time_zone="Europe/London",
parameter_values={},
cloud_scheduler_service_account="<your-service-account>#<project_id>.iam.gserviceaccount.com"
)
If you are still stuck, it is also useful to run gcloud scheduler jobs describe <pipeline-name> as it really helps to understand what scheduler is doing. You'll see cloudfunction url, POST payload which is some base64 encoded and contains pipeline yaml and you'll see that it is using OIDC/service account for security. Also useful is to view the code of the 'templated_http_request-v1' cloud function (sneakily created!). I was able to invoke the cloudfunction from POSTMAN using the payload obtained from scheduler job.
I have a requirement where I need to trigger a cloud function which in turn triggers a data flow job once a file is placed in google cloud storage bucket of another project. Google documentation says its not possible, please see here https://cloud.google.com/functions/docs/calling/storage
However, I tried doing this and my cloud function failed to deploy with below error. It says
Looks like this is a permission issue and if required permission are given , this will work.
Do I need to add and give owner permission to #appspot.gserviceaccount.com of the project(project A) from where I am trying to access the bucket of another project(Project B)
So if the above is true, In my project B IAM page, I will see 2 as below
#appspot.gserviceaccount.com OWNER
#appspot.gserviceaccount.com EDITOR
Any inputs on this is much appreciated.
It's not possible to catch event from other projects for now. But there is a workaround.
In the project with the bucket, create a PubSub notification on Cloud Storage
On the topic that you created, create a push subscription. Use the Cloud Functions URL, and secure the PubSub call (you can get inspiration from there. If you are stuck, let me know, I will take more time to describe this part)
On the Cloud Functions grant the PubSub service account as cloudfunctions.invoker role
EDIT 1
The security part isn't so easy at the beginning. In your project B (where you have your Cloud Storage), you have created a PubSub topic. On this topic you can create a notification with a service account created in the project B. Take care to well fill in the audience
Then, you need to grant this "project B" service account as roles/cloudfunctions.invoker on the Cloud Function of the project A
# Create the service account
gcloud iam service-accounts create pubsub-push --project=<ProjectB>
#Create the push subscription
gcloud pubsub subscriptions create \
--push-endpoint=https://<region>-<projectA>.cloudfunctions.net/<functionName> \
--push-auth-service-account=pubsub-push#<projectB>.iam.gserviceaccount.com \
--push-auth-token-audience=https://<region>-<projectA>.cloudfunctions.net/<functionName> \
--topic=<GCSNotifTopic> --project=<ProjectB>
#Grant the service account
gcloud functions add-iam-policy-binding --member=serviceAccount:pubsub-push#<ProjectB>.iam.gserviceaccount.com --role=roles/cloudfunctions.invoker <FunctionName> --project=<projectA>
Last traps:
The Cloud Functions in the project A haven't the same signature if it's an HTTP functions (callable by a pubsub push subscription) or a Background Function (callable by events, such as CLoud Storage event). You need to update this according to the documentation
The PubSub message sent to the Cloud Functions is slightly different. Take care to update the input param accordingly.
Google documentation says its not possible
This is all you need to know. It is not possible. There are no workarounds, regardless of what sort of error messages you might see.
I have deployed simple PubSub Cloud Function trigger using this tutorial: https://medium.com/#milosevic81/copy-data-from-pub-sub-to-bigquery-496e003228a1
For test I pushed large (over 8MB) message to PubSub topic.
As a result Cloud function returned the following error message to the log: Function execution could not start, status: 'request too large'
The issue is, that Cloud Function started to fire up constantly producing constant resource usage and log messages. It stopped only after I manually purged the related PubSub topic.
Is there a mechanism/configuration to prevent such behavior? Ideally PubSub message should not be picked again after Cloud Function trigger execution.
You reached the quotas of Cloud Functions
Max uncompressed HTTP request size -> 10MB
One solution is to use Cloud Run (the quotas is higher, 32Mb)
For this, you need several changes
Convert your Cloud Functions in Cloud Run. I wrote an article (not dedicated to this but you have an example in Python), and I presented this at GDG Ahmedabad last month, in GO this time
Create a push subscription on your PubSub topic and use the Cloud Run HTTPS endpoint in the "push" HTTP field
Cloud Run can handle up to 80 concurrent requests on 1 instances, Cloud Functions only one. Because your request are "big" it might cause memory issues if you process too many request in the same instance. You can control this with Cloud Run with the --concurrency param. Set it to 1 to have the same behavior as CLoud Functions.
I'm triggering a cloud function every minute with cloud scheduler [* * * * *].
The Stackdriver logs indicate the function appears to have been triggered and run twice in the same minute. Is this possible?
PubSub promises at least once delivery but I assumed that GCP would automatically handle duplicate triggers for scheduler -> function workflows.
What is a good pattern for preventing this function from running more than once per minute?
Your function needs to be made "idempotent" in order to ensure that a message gets processed only once. In other words, you'll have to maintain state somewhere (maybe a database) that a message was processed successfully, and check that state to make sure a message doesn't get processed twice.
All non-HTTP type Cloud Functions provide a unique event ID in the context parameter provided to the function invocation. If you see a repeat event ID, that means your function is being invoked again for the same message, for whatever reason.
This need for idempotence is not unique to pubsub or cloud scheduler. It's a concern for all non-HTTP type background functions.
A full discussion on writing idempotent functions is a bit too much a Stack Overflow answer, but there is a post in the Google Cloud blog that covers the issue pretty well.
See also: Cloud functions and Firebase Firestore with Idempotency