Skip to content

Cloud Run Jobs

  • Client: google-cloud-run (run_v2.JobsClient / run_v2.ExecutionsClient)
  • Transport: gRPC (the client default). drongo forces the client onto its REST transport for the mock scope.
  • Backend: per-project.

Use the normal clients with no transport argument.

Long-running operations complete synchronously

Cloud Run's mutating calls (create_job, run_job, delete_job) return a long-running operation (LRO). drongo completes each one synchronously and returns a done operation, so .result() returns immediately with the final resource. There is no real container execution. Errors surface as REST-style exceptions (a duplicate job raises Conflict).

Create and run a job

create_job and run_job return an LRO; call .result() to get the resource:

from drongo import mock_gcp

PARENT = "projects/my-project/locations/us-central1"


@mock_gcp
def test_run_job():
    from google.cloud import run_v2

    jobs = run_v2.JobsClient()  # default, no transport arg
    executions = run_v2.ExecutionsClient()

    job = run_v2.Job(
        template=run_v2.ExecutionTemplate(
            template=run_v2.TaskTemplate(
                containers=[run_v2.Container(image="gcr.io/my-project/batch")]
            )
        )
    )
    created = jobs.create_job(
        request={"parent": PARENT, "job": job, "job_id": "nightly"}
    ).result(timeout=10)
    assert created.name == f"{PARENT}/jobs/nightly"

    # Running the job creates an execution.
    execution = jobs.run_job(request={"name": f"{PARENT}/jobs/nightly"}).result(
        timeout=10
    )
    assert execution.name.startswith(f"{PARENT}/jobs/nightly/executions/")

Executions

@mock_gcp
def test_executions():
    from google.cloud import run_v2

    jobs = run_v2.JobsClient()
    executions = run_v2.ExecutionsClient()
    job = run_v2.Job(
        template=run_v2.ExecutionTemplate(
            template=run_v2.TaskTemplate(
                containers=[run_v2.Container(image="gcr.io/p/img")]
            )
        )
    )
    jobs.create_job(request={"parent": PARENT, "job": job, "job_id": "batch"}).result()
    jobs.run_job(request={"name": f"{PARENT}/jobs/batch"}).result()

    listed = list(
        executions.list_executions(request={"parent": f"{PARENT}/jobs/batch"})
    )
    assert len(listed) == 1
    fetched = executions.get_execution(request={"name": listed[0].name})
    assert fetched.name == listed[0].name

Delete a job

@mock_gcp
def test_delete_job():
    from google.cloud import run_v2
    from google.api_core import exceptions as gexc

    jobs = run_v2.JobsClient()
    job = run_v2.Job(
        template=run_v2.ExecutionTemplate(
            template=run_v2.TaskTemplate(
                containers=[run_v2.Container(image="gcr.io/p/img")]
            )
        )
    )
    jobs.create_job(request={"parent": PARENT, "job": job, "job_id": "batch"}).result()

    jobs.delete_job(request={"name": f"{PARENT}/jobs/batch"}).result(timeout=10)
    try:
        jobs.get_job(request={"name": f"{PARENT}/jobs/batch"})
    except gexc.NotFound:
        pass

Coverage

Operation Status
Create / get / list / delete job Supported
run_job (creates an execution) Supported
Executions: get / list / delete Supported
Long-running operations (.result()) Supported (completed synchronously)
Actual container execution Planned (no real compute)
Cloud Run services (serving), revisions, traffic Planned