# Build and create a Python job in Cloud Run

Learn how to create a simple Cloud Run job, then deploy from source, which automatically packages your code into a container image, uploads the container image to Artifact Registry, and then deploys to Cloud Run. You can use other languages in addition to the ones shown.

<br />

## Before you begin

1.


   Enable the Cloud Run Admin API and Cloud Build APIs, if any are not already enabled:


   **Roles required to enable APIs**


   To enable APIs, you need the `serviceusage.services.enable` permission. If you
   created the project, then you likely already have this permission through the
   Owner role (`roles/owner`). Otherwise, you can get this permission through the
   Service Usage Admin role (`roles/serviceusage.serviceUsageAdmin`).
   [Learn how to grant roles](https://docs.cloud.google.com/iam/docs/granting-changing-revoking-access.md.txt).

   ```bash
   gcloud services enable run.googleapis.com cloudbuild.googleapis.com
   ```

   After the Cloud Run Admin API is enabled, the Compute Engine default service account is
   automatically created.
2. Review [Cloud Run
   pricing](https://cloud.google.com/run/pricing) or estimate costs with the [pricing calculator](https://cloud.google.com/products/calculator).

<br />

### Required roles


To get the permissions that
you need to complete this quickstart,

ask your administrator to grant you the
following IAM roles:

- [Cloud Run Admin](https://docs.cloud.google.com/iam/docs/roles-permissions/run.md.txt#run.admin) (`roles/run.admin`) on the project
- [Cloud Run Source Developer](https://docs.cloud.google.com/iam/docs/roles-permissions/run.md.txt#run.sourceDeveloper) (`roles/run.sourceDeveloper`) on the project
- [Service Account User](https://docs.cloud.google.com/iam/docs/roles-permissions/iam.md.txt#iam.serviceAccountUser) (`roles/iam.serviceAccountUser`) on the service identity
- [Logs Viewer](https://docs.cloud.google.com/iam/docs/roles-permissions/logging.md.txt#logging.viewer) (`roles/logging.viewer`) on the project


For more information about granting roles, see [Manage access to projects, folders, and organizations](https://docs.cloud.google.com/iam/docs/granting-changing-revoking-access.md.txt).


You might also be able to get
the required permissions through [custom
roles](https://docs.cloud.google.com/iam/docs/creating-custom-roles) or other [predefined
roles](https://docs.cloud.google.com/iam/docs/roles-overview#predefined).

### Grant the Cloud Build service account access to your project

Cloud Build automatically uses the [Compute Engine default
service account](https://docs.cloud.google.com/build/docs/cloud-build-service-account) as the default
Cloud Build service account to build your source code and
Cloud Run resource, unless you override this behavior.

For Cloud Build to build your sources, grant the Cloud Build service
account the [Cloud Run
Builder](https://docs.cloud.google.com/iam/docs/roles-permissions/run#run.builder)
(`roles/run.builder`) role on your project:

```bash
gcloud projects add-iam-policy-binding PROJECT_ID \
    --member=serviceAccount:SERVICE_ACCOUNT_EMAIL_ADDRESS \
    --role=roles/run.builder
```

Replace `PROJECT_ID` with your Google Cloud
project ID and `SERVICE_ACCOUNT_EMAIL_ADDRESS` with the
email address of the Cloud Build service account. If you're using the
Compute Engine default service account as the Cloud Build service account, then
use the following format for the service account email address:

```bash
PROJECT_NUMBER-compute@developer.gserviceaccount.com
```

Replace `PROJECT_NUMBER` with your Google Cloud
project number.

For detailed instructions on how to find your project ID, and project number,
see [Creating
and managing projects](https://docs.cloud.google.com/resource-manager/docs/creating-managing-projects#identifying_projects).

Granting the Cloud Run builder role takes a couple of minutes to [propagate](https://docs.cloud.google.com/iam/docs/access-change-propagation.md.txt).

## Writing the sample job

<br />

To write a job in Python:

1. Create a new directory named `jobs` and change directory
   into it:

   ```python
   mkdir jobs
   cd jobs
   ```
2. Create a `main.py` file for the actual job code. Copy the following sample lines
   into it:

   ```python
   import json
   import os
   import random
   import sys
   import time

   # Retrieve Job-defined env vars
   TASK_INDEX = os.getenv("CLOUD_RUN_TASK_INDEX", 0)
   TASK_ATTEMPT = os.getenv("CLOUD_RUN_TASK_ATTEMPT", 0)
   # Retrieve User-defined env vars
   SLEEP_MS = os.getenv("SLEEP_MS", 0)
   FAIL_RATE = os.getenv("FAIL_RATE", 0)


   # Define main script
   def main(sleep_ms=0, fail_rate=0):
       """Program that simulates work using the sleep method and random failures.

       Args:
           sleep_ms: number of milliseconds to sleep
           fail_rate: rate of simulated errors
       """
       print(f"Starting Task #{TASK_INDEX}, Attempt #{TASK_ATTEMPT}...")
       # Simulate work by waiting for a specific amount of time
       time.sleep(float(sleep_ms) / 1000)  # Convert to seconds

       # Simulate errors
       random_failure(float(fail_rate))

       print(f"Completed Task #{TASK_INDEX}.")


   def random_failure(rate):
       """Throws an error based on fail rate

       Args:
           rate: a float between 0 and 1
       """
       if rate < 0 or rate > 1:
           # Return without retrying the Job Task
           print(
               f"Invalid FAIL_RATE env var value: {rate}. "
               + "Must be a float between 0 and 1 inclusive."
           )
           return

       random_failure = random.random()
       if random_failure < rate:
           raise Exception("Task failed.")


   # Start script
   if __name__ == "__main__":
       try:
           main(SLEEP_MS, FAIL_RATE)
       except Exception as err:
           message = (
               f"Task #{TASK_INDEX}, " + f"Attempt #{TASK_ATTEMPT} failed: {str(err)}"
           )

           print(json.dumps({"message": message, "severity": "ERROR"}))
           sys.exit(1)  # Retry Job Task by exiting the process
   ```

   Cloud Run jobs allows users to specify the number of tasks the job is
   to execute. This sample code shows how to use the built-in `CLOUD_RUN_TASK_INDEX`
   environment variable. Each task represents one running copy of the container.
   Note that tasks are usually executed in parallel. Using multiple tasks is useful
   if each task can independently process a subset of your data.

   Each task is aware of its index, stored in the `CLOUD_RUN_TASK_INDEX`
   environment variable. The built-in `CLOUD_RUN_TASK_COUNT` environment variable
   contains the number of tasks supplied at job execution time via the `--tasks`
   parameter.

   The code shown also shows how to retry tasks, using the built-in
   `CLOUD_RUN_TASK_ATTEMPT` environment variable, which contains the number of
   times this task has been retried, starting at 0 for the first attempt and
   incrementing by 1 for every successive retry, up to `--max-retries`.

   The code also lets you generate failures as a way to test retries
   and to generate error logs so you can see what those look like.
3. Create a text file named `Procfile` with no file extension, containing the
   following:

   ```python
   web: python3 main.py
   ```

Your code is complete and ready to be packaged in a container.

## Build jobs container, send it to Artifact Registry and deploy to Cloud Run

This quickstart uses deploy from source, which builds the container, uploads it
to Artifact Registry, and deploys the job to Cloud Run:

```bash
gcloud run jobs deploy job-quickstart \
    --source . \
    --tasks 50 \
    --set-env-vars SLEEP_MS=10000 \
    --set-env-vars FAIL_RATE=0.1 \
    --max-retries 5 \
    --region REGION \
    --project=PROJECT_ID
```

where <var translate="no">PROJECT_ID</var> is your project ID and <var translate="no">REGION</var> is your
region, for example, `europe-west1`. Note that you can
change the various parameters to whatever values you want to use for your
testing purposes. `SLEEP_MS` simulates work and `FAIL_RATE` causes `X`% of tasks
to fail so you can experiment with parallelism and retrying failing tasks.

## Execute a job in Cloud Run

To execute the job you just created:

<br />

```bash
gcloud run jobs execute job-quickstart --region REGION
```

<br />

Replace <var translate="no">REGION</var> with the region you used when you created and deployed
the job, for example `europe-west1`.

> [!TIP]
> **Success:** You created and executed a job using the Python runtime in Cloud Run.

## Clean up

To avoid additional charges to your Google Cloud account, delete all the resources
you deployed with this quickstart.

### Delete your repository

Cloud Run only charges for the time your job executes.
However, you might still be [charged for storing the container image in
Artifact Registry](https://cloud.google.com/artifact-registry/pricing). To delete Artifact Registry repositories,
follow the steps in [Delete
repositories](https://docs.cloud.google.com/artifact-registry/docs/manage-repos#delete) in the Artifact Registry
documentation.

### Delete your job

Cloud Run jobs only incur cost when a job task is executing.
To delete your Cloud Run job, follow one of these steps:

### Console

To delete a job:

1. In the Google Cloud console, go to Cloud Run:

   [Go to Cloud Run](https://console.cloud.google.com/run/jobs)
2. Locate the job you want to delete in the jobs list, and click
   its checkbox to select it.

3. Click **Delete**. This terminates all the job executions in progress and
   all running container instances.

### gcloud

To delete a job, run the following command:

```bash
gcloud run jobs delete JOB_NAME
```

Replace `JOB_NAME` with the name of the job.

### Delete your test project

Deleting your Google Cloud project stops billing for all resources in that
project. To release all Google Cloud resources in your project, follow these steps:

> [!CAUTION]
> **Caution** : Deleting a project has the following effects:
>
> - **Everything in the project is deleted.** If you used an existing project for the tasks in this document, when you delete it, you also delete any other work you've done in the project.
> - **Custom project IDs are lost.** When you created this project, you might have created a custom project ID that you want to use in the future. To preserve the URLs that use the project ID, such as an `appspot.com` URL, delete selected resources inside the project instead of deleting the whole project.

1. Delete a Google Cloud project:

```
gcloud projects delete PROJECT_ID
```

<br />

## What's next

For more information on building a container from code source and pushing to
a repository, see:

- [Developing Cloud Run services](https://docs.cloud.google.com/run/docs/developing.md.txt)
- [Building Containers](https://docs.cloud.google.com/run/docs/building/containers.md.txt)
- [Test a Cloud Run service locally](https://docs.cloud.google.com/run/docs/testing/local.md.txt)
- [Deploying from source code](https://docs.cloud.google.com/run/docs/deploying-source-code.md.txt)