# Cloud Run Functions and Eventarc — Google Cloud Platform

Source: https://www.skillbyai.com/en/gcp/s-functions

> Run small functions in response to HTTP requests and cloud events.

## Functions on top of Cloud Run

**Cloud Run functions** (formerly *Cloud Functions*) let you deploy a single function in Node.js, Python, Go, Java, .NET, Ruby or PHP; Google builds it into a container and runs it on Cloud Run infrastructure. Functions are triggered by **HTTP** or by **events** delivered through **Eventarc**, which routes events in the **CloudEvents** format from sources such as Cloud Storage (object finalised), Pub/Sub messages, Firestore changes and **Cloud Audit Logs** (almost any API call). Event-triggered functions can be retried on failure, so they must be **idempotent**. Keep functions small and focused; once you have several related endpoints, a regular Cloud Run service is often easier to organise and test.

## From event source to function

Eventarc carries an event from a source to the function as a CloudEvent.

![A bucket icon and a message icon on the left sending arrows through a central router shape into a small function block on the right.](assets/figures/gcp/section-4-map.svg) — Figure 4.1 — Event sources, Eventarc routing and a function.

## A function triggered by a new Cloud Storage object

The Functions Framework decorator marks the CloudEvent handler.

```python
import functions_framework

@functions_framework.cloud_event
def on_upload(event):
    data = event.data
    bucket, name = data["bucket"], data["name"]
    if not name.startswith("uploads/"):
        return  # ignore our own thumbnails to avoid loops
    print(f"new object gs://{bucket}/{name}, size {data.get('size')}")

# deploy:
# gcloud functions deploy on-upload --gen2 --runtime=python312 --region=asia-south1 \
#   --entry-point=on_upload --source=. \
#   --trigger-event-filters="type=google.cloud.storage.object.v1.finalized" \
#   --trigger-event-filters="bucket=shop-dev-assets-123"
```

## Avoid trigger loops

A function that writes to the same bucket that triggers it can call itself forever and run up a bill. Write output to a different bucket or prefix and filter on it.

**Quiz:** Why must event-triggered functions be idempotent?

- [ ] Because they are always public
- [ ] Because Eventarc deletes duplicates
- [x] Because events can be delivered more than once when retries happen
- [ ] Because functions cannot write to databases

*Answer:* Because events can be delivered more than once when retries happen. At-least-once delivery and retries mean the same event may arrive twice.
