Skip to content

GCP.Run reference

Source: packages/gcp/src/Run/BindContainer.ts

Run a Container as a sidecar and reach one of its ports directly — for a protocol other than HTTP, such as Redis or Postgres. See bindContainer.

export const Cache = GCP.Run.Container("Cache", {
image: "docker.io/library/redis:7",
port: 6379,
startupProbe: { tcpSocket: {} },
});
// inside the service's Effect
const cache = yield* GCP.Run.bindPort(Cache, 6379);
// cache.url === "http://localhost:6379"; connect with `redis://localhost:${cache.port}`

Source: packages/gcp/src/Run/Container.ts

A container that runs next to a Cloud Run service’s main container, in the same instance. Bind it from the service with bindContainer (typed RPC and fetch) or bindPort (a raw port): binding adds it to the service’s revision and holds the service back until the container passes its startup probe.

Give it main and an Effect implementation to run your own program — Alchemy bundles it into its own image — or just an image.

An Effect-native container with RPC methods

export default class Worker extends GCP.Run.Container<Worker>()(
"Worker",
{
main: import.meta.url,
port: 3000,
startupProbe: { httpGet: { path: "/health" } },
},
Effect.gen(function* () {
return {
greet: (name: string) => Effect.succeed(`hello ${name}`),
fetch: Effect.succeed(HttpServerResponse.text("ok")),
};
}),
) {}

An image

export const Cache = GCP.Run.Container("Cache", {
image: "docker.io/library/redis:7",
port: 6379,
startupProbe: { tcpSocket: {} },
});
export default class Worker extends GCP.Run.Container<Worker>()(
"Worker",
{ main: import.meta.url, port: 3000 },
Effect.gen(function* () {
const publish = yield* GCP.PubSub.Publish(Tweets);
return {
post: (text: string) =>
publish({ body: { messages: [{ data: btoa(text) }] } }),
};
}).pipe(Effect.provide(GCP.PubSub.PublishHttp)),
) {}

The binding’s env lands on this container. Its IAM roles go to the service account of the revision the container joins.

Source: packages/gcp/src/Run/EffectApis.ts

Serve an Effect RPC group as a Cloud Run service’s or container’s fetch. Uses NDJSON, the serialization the schema clients of bindContainer and InvokeService speak, so value and streaming procedures both work.

export default class Tasks extends GCP.Run.Container<Tasks>()(
"Tasks",
{ main: import.meta.url, port: 3000 },
Effect.gen(function* () {
return {
fetch: GCP.Run.ServeRpc(TaskRpcs, TaskRpcs.toLayer({
getTask: ({ id }) => Effect.succeed(new Task({ id, title: "write docs" })),
})),
};
}),
) {}

Source: packages/gcp/src/Run/EventarcEventSource.ts Kind: Layer · Provides: GCP.Eventarc.EventSource

HTTP implementation of GCP.Eventarc.EventSource for GCP.Run.Service / GCP.Function and GCP.CloudFunctions.Function.

Deploy-time: grants the host’s runtime service account roles/eventarc.eventReceiver on the project and roles/run.invoker on the host (and, for Cloud Storage events, the Storage service agent roles/pubsub.publisher on the project, which direct Storage events require), then creates the trigger with that account as its identity. Each grant and the trigger block until GCP reports them in place and healthy. Runtime: claims deliveries on the path, verifies the OIDC token, decodes the binary-mode CloudEvent, and runs the handler; a 2xx acks, a failed handler answers 500 and Eventarc redelivers.

Source: packages/gcp/src/Run/GetService.ts

Runtime binding for Cloud Run services.get.

Bind this operation to a Service in a Function/Action init phase. Provide GetServiceHttp.

const getService = yield* GCP.Run.GetService(api);
const live = yield* getService();

Source: packages/gcp/src/Run/GetServiceHttp.ts Kind: Layer · Provides: GCP.Run.GetService

HTTP implementation of GetService.

Source: packages/gcp/src/Run/GetWorkerPool.ts

Runtime binding for Cloud Run workerPools.get.

Bind this operation to a WorkerPool in a Function/Action init phase. Provide GetWorkerPoolHttp.

const getWorkerPool = yield* GCP.Run.GetWorkerPool(pool);
const live = yield* getWorkerPool();

Source: packages/gcp/src/Run/GetWorkerPoolHttp.ts Kind: Layer · Provides: GCP.Run.GetWorkerPool

HTTP implementation of GetWorkerPool.

Source: packages/gcp/src/Run/InvokeServiceHttp.ts Kind: Layer · Provides: GCP.Run.InvokeService

HTTP implementation of InvokeService: ID tokens from the Cloud Run metadata server, requests over the ambient HttpClient.

Source: packages/gcp/src/Run/Job.ts

A Cloud Run Job — a container that runs to completion.

Changing jobId or location replaces the job.

Generated name

const job = yield* GCP.Run.Job("Migrate", {
containers: [
{ image: "us-docker.pkg.dev/cloudrun/container/job:latest" },
],
});

Explicit id, labels, and retries

const job = yield* GCP.Run.Job("Migrate", {
jobId: "order-migrate",
location: "us-central1",
labels: { env: "prod" },
maxRetries: 1,
timeout: "120s",
containers: [
{
image: "us-docker.pkg.dev/cloudrun/container/job:latest",
env: [{ name: "STAGE", value: "prod" }],
},
],
});
export class Warm extends GCP.Run.Job<Warm>()(
"Warm",
{ main: import.meta.url },
Effect.gen(function* () {
const redis = yield* GCP.Redis.ReadWriteRedis(cache);
return {
run: redis.set("warmed", "1"),
};
}).pipe(Effect.provide(GCP.Redis.ReadWriteRedisHttp)),
) {}

Builds reuse the local BuildKit cache of the machine they run on, and nothing but the image is pushed. A builder that has never built the image, such as a fresh CI runner, reruns every step. Set build.cache: true to keep every stage’s layers at the image repository’s :buildcache tag, so fresh builders skip unchanged steps. For another backend, pass BuildKit’s own --cache-from / --cache-to values as from and to.

Cache layers in Artifact Registry

const migrate = yield* GCP.Run.Job("Migrate", {
main: import.meta.url,
build: { cache: true },
});

Cache layers in GitHub Actions

const migrate = yield* GCP.Run.Job("Migrate", {
main: import.meta.url,
build: {
cache: {
from: ["type=gha,scope=migrate"],
to: ["type=gha,scope=migrate,mode=max"],
},
},
});
const runJob = yield* GCP.Run.RunJob(job);
yield* runJob();

Source: packages/gcp/src/Run/RunJob.ts

Runtime binding for Cloud Run jobs.run.

Triggers a new execution of the bound Job. Provide RunJobHttp.

Trigger an execution

const runJob = yield* GCP.Run.RunJob(job);
yield* runJob();

Override task count

const runJob = yield* GCP.Run.RunJob(job);
yield* runJob({
body: { overrides: { taskCount: 1 } },
});

Source: packages/gcp/src/Run/RunJobHttp.ts Kind: Layer · Provides: GCP.Run.RunJob

HTTP implementation of RunJob.

Source: packages/gcp/src/Run/ScheduleEventSource.ts Kind: Layer · Provides: GCP.CloudScheduler.ScheduleEventSource

Implementation of GCP.CloudScheduler.ScheduleEventSource for HTTP hosts (GCP.Run.Service / GCP.Function, GCP.CloudFunctions.Function).

Deploy-time: grants the host’s runtime service account roles/run.invoker on the host and creates a Cloud Scheduler job that POSTs to the host’s URL with an OIDC token for that account. Runtime: claims the job’s deliveries on its path, verifies the token, and runs the handler with the X-CloudScheduler-* headers. 204 marks the run successful; a failed handler answers 500 and the job’s retry policy applies.

ScheduleEventSource: Running on a schedule

Section titled “ScheduleEventSource: Running on a schedule”
Effect.gen(function* () {
yield* GCP.CloudScheduler.consumeSchedule(
"Sweep",
{ schedule: "every 5 minutes" },
(event) => Effect.log(`sweep ${event.scheduleTime}`),
);
}).pipe(Effect.provide(GCP.Run.ScheduleEventSource));

Source: packages/gcp/src/Run/Service.ts

A Cloud Run service (Knative serving revision + traffic).

Changing serviceId or location replaces the service. Updates to template create a new revision.

This is GCP’s effectful HTTP platform — the analog of AWS.Lambda.Function / Cloudflare.Worker. Pass main plus an Effect implementation; bindings grant IAM onto the runtime service account and inject env, the way AWS policyStatements land on the execution role.

Generated name, default hello image

const api = yield* GCP.Run.Service("api", {});

Explicit id, image, env, and labels

const api = yield* GCP.Run.Service("api", {
serviceId: "order-api",
location: "us-central1",
description: "order HTTP API",
labels: { env: "prod" },
ingress: "INGRESS_TRAFFIC_ALL",
template: {
timeout: "60s",
containers: [
{
image: "us-docker.pkg.dev/cloudrun/container/hello",
env: [{ name: "ENV", value: "prod" }],
},
],
},
});

HTTP startup probe, with a proxy that starts after the app

const api = yield* GCP.Run.Service("api", {
template: {
containers: [
{
name: "proxy",
image: proxyImage,
ports: [{ name: "h2c", containerPort: 8080 }],
dependsOn: ["app"],
},
{
name: "app",
image: appImage,
startupProbe: {
httpGet: { path: "/health", port: 3000 },
periodSeconds: 2,
failureThreshold: 30,
},
livenessProbe: { httpGet: { path: "/health", port: 3000 }, periodSeconds: 10 },
},
],
},
});

TCP and gRPC probes

startupProbe: { tcpSocket: { port: 5432 }, initialDelaySeconds: 5 },
livenessProbe: { grpc: { port: 9090, service: "health" }, timeoutSeconds: 3 },

Changing a probe or dependsOn rolls a new revision. Removing startupProbe restores Cloud Run’s default TCP probe.

Effect-native service with a sidecar

export class Api extends GCP.Run.Service<Api>()(
"Api",
{
main: import.meta.url,
template: {
containers: [
{
// image, ports and env are filled in from `main`
startupProbe: { httpGet: { path: "/health" } },
dependsOn: ["cache"],
},
{
name: "cache",
image: "docker.io/library/redis:7",
startupProbe: { tcpSocket: { port: 6379 } },
},
],
},
},
Effect.gen(function* () {
return {
fetch: Effect.gen(function* () {
const request = yield* HttpServerRequest;
if (request.url === "/health") return HttpServerResponse.text("ok");
return HttpServerResponse.text("hello");
}),
};
}),
) {}

The first container runs main; the rest deploy as sidecars.

An image service with an Effect-native sidecar

const worker = yield* Worker; // a GCP.Run.Container
const api = yield* GCP.Run.Service("api", {
template: {
containers: [
{ image: proxyImage, ports: [{ containerPort: 8080 }], dependsOn: [worker.name] },
worker,
],
},
});

A listed Container brings its bindings’ roles and the sidecars it binds. worker.name is an Output that resolves to the container’s name in the revision, so the proxy starts after it.

Service: Effect-native Function with bindings

Section titled “Service: Effect-native Function with bindings”
const tweets = yield* GCP.PubSub.Topic("tweets", {});
const cache = yield* GCP.Redis.Instance("Cache", { memorySizeGb: 1 });
export class TweetBot extends GCP.Run.Service<TweetBot>()(
"TweetBot",
{ main: import.meta.url },
Effect.gen(function* () {
const publish = yield* GCP.PubSub.Publish(tweets);
const redis = yield* GCP.Redis.ReadWriteRedis(cache);
return {
fetch: Effect.gen(function* () {
const text = (yield* redis.get("last-tweet")) ?? "hello twitter";
yield* publish({
body: { messages: [{ data: btoa(text) }] },
});
return HttpServerResponse.text("queued");
}),
};
}).pipe(
Effect.provide([
GCP.PubSub.PublishHttp,
GCP.Redis.ReadWriteRedisHttp,
]),
),
) {}

An AWS binding gives the service an IAM role that trusts its runtime service account’s Google ID tokens. The service assumes the role with AssumeRoleWithWebIdentity, so no AWS access key is created.

const jobs = yield* AWS.SQS.Queue("Jobs");
export class Api extends GCP.Run.Service<Api>()(
"Api",
{ main: import.meta.url },
Effect.gen(function* () {
const send = yield* AWS.SQS.SendMessage(jobs);
return {
fetch: send({ MessageBody: "hello" }).pipe(
Effect.as(HttpServerResponse.text("sent")),
),
};
}).pipe(Effect.provide(AWS.SQS.SendMessageHttp)),
) {}

Builds reuse the local BuildKit cache of the machine they run on, and nothing but the image is pushed. A builder that has never built the image, such as a fresh CI runner, reruns every step. Set build.cache: true to keep every stage’s layers at the image repository’s :buildcache tag, so fresh builders skip unchanged steps. For another backend, pass BuildKit’s own --cache-from / --cache-to values as from and to.

Cache layers in Artifact Registry

const api = yield* GCP.Run.Service("Api", {
main: import.meta.url,
build: { cache: true },
});

Cache layers in GitHub Actions

const api = yield* GCP.Run.Service("Api", {
main: import.meta.url,
build: {
cache: {
from: ["type=gha,scope=api"],
to: ["type=gha,scope=api,mode=max"],
},
},
});
const api = yield* GCP.Run.Service("api", {
template: {
timeout: "120s",
containers: [{ image: "us-docker.pkg.dev/cloudrun/container/hello" }],
},
});

Template changes create a new revision. The runtime service account is kept.

const getService = yield* GCP.Run.GetService(api);
const live = yield* getService();

Source: packages/gcp/src/Run/TopicEventSource.ts Kind: Layer · Provides: GCP.PubSub.TopicEventSource

Push implementation of GCP.PubSub.TopicEventSource for HTTP hosts (GCP.Run.Service / GCP.Function, GCP.CloudFunctions.Function).

Deploy-time: grants the host’s runtime service account roles/run.invoker on the host and creates a push subscription to the host’s URL, signed with an OIDC token for that account. Runtime: claims POST deliveries on the push path, verifies the token, and runs the handler. 204 acks the message; a failed handler answers 500 and Pub/Sub redelivers per the subscription’s retry policy.

Source: packages/gcp/src/Run/TopicPullEventSource.ts Kind: Layer · Provides: GCP.PubSub.TopicEventSource

Pull implementation of GCP.PubSub.TopicEventSource for hosts without an inbound URL (GCP.Run.Job, GCP.Run.WorkerPool; any host with ServerHost).

Deploy-time: creates a pull subscription owned by the host and grants the host’s runtime service account roles/pubsub.subscriber on it (through the Pull / Acknowledge bindings). Runtime: a background loop pulls batches, runs the handler, and acks the batch once the handler succeeds. A failed handler leaves the batch unacked, so Pub/Sub redelivers after the ack deadline.

Source: packages/gcp/src/Run/WorkerPool.ts

A Cloud Run worker pool (pull-based revision + instance split).

Changing workerPoolId or location replaces the pool. Updates to template create a new revision.

Generated name, default worker image

const pool = yield* GCP.Run.WorkerPool("workers", {});

Explicit id, image, env, and labels

const pool = yield* GCP.Run.WorkerPool("workers", {
workerPoolId: "order-workers",
location: "us-central1",
description: "order pull workers",
labels: { env: "prod" },
scaling: { manualInstanceCount: 1 },
template: {
containers: [
{
image: "us-docker.pkg.dev/cloudrun/container/worker-pool",
env: [{ name: "ENV", value: "prod" }],
},
],
},
});
const getWorkerPool = yield* GCP.Run.GetWorkerPool(pool);
const live = yield* getWorkerPool();

WorkerPool: Effect-native Worker Pool with bindings

Section titled “WorkerPool: Effect-native Worker Pool with bindings”
export class Workers extends GCP.Run.WorkerPool<Workers>()(
"Workers",
{ main: import.meta.url, scaling: { manualInstanceCount: 1 } },
Effect.gen(function* () {
const redis = yield* GCP.Redis.ReadWriteRedis(cache);
return {
run: redis.set("worker", "up"),
};
}).pipe(Effect.provide(GCP.Redis.ReadWriteRedisHttp)),
) {}