1import * as GCP from "@/GCP";
2import * as Effect from "effect/Effect";
3import { serveProbes } from "../../bindingHost.ts";
4
5/**
6 * Memorystore instance create + delete runs well past 5 minutes, so the
7 * instance (and every binding on it) is only declared with
8 * `GCP_TEST_SLOW=1`. The flag is forwarded to the host's environment so the
9 * deployed runtime binds the same set.
10 */
11export const slow = !!process.env.GCP_TEST_SLOW && !process.env.FAST;
12
13/** AUTH-enabled instance: data-plane bindings fetch the AUTH string. */
14export const Cache = GCP.Redis.Instance("Cache", {
15 location: "us-central1",
16 tier: "BASIC",
17 memorySizeGb: 1,
18 authEnabled: true,
19});
20
21export const Acl = GCP.Redis.AclPolicy("Acl", {
22 location: "us-central1",
23 rules: [{ username: "reader", rule: "on ~cache:* +get" }],
24});
25
26export const WRITTEN_KEY = "bindings:written";
27export const WRITTEN_VALUE = "from-write-redis";
28
29const instanceProbes = Effect.gen(function* () {
30 const getInstance = yield* GCP.Redis.GetInstance(Cache);
31 const getAuthString = yield* GCP.Redis.GetAuthString(Cache);
32 const read = yield* GCP.Redis.ReadRedis(Cache);
33 const write = yield* GCP.Redis.WriteRedis(Cache);
34 const readWrite = yield* GCP.Redis.ReadWriteRedis(Cache);
35 return {
36 getInstance: getInstance(),
37 getAuthString: getAuthString(),
38 writeRedis: Effect.gen(function* () {
39 yield* write.set(WRITTEN_KEY, WRITTEN_VALUE);
40 return { incremented: yield* write.incr("bindings:counter") };
41 }),
42 readRedis: Effect.gen(function* () {
43 return {
44 value: yield* read.get(WRITTEN_KEY),
45 exists: yield* read.exists(WRITTEN_KEY),
46 pong: yield* read.ping(),
47 };
48 }),
49 readWriteRedis: Effect.gen(function* () {
50 yield* readWrite.set("bindings:roundtrip", "rw");
51 const value = yield* readWrite.get("bindings:roundtrip");
52 const deleted = yield* readWrite.del("bindings:roundtrip");
53 return { value, deleted };
54 }),
55 };
56});
57
58/**
59 * Effect-native Cloud Run service exercising every Memorystore for Redis
60 * binding as its own runtime service account. It joins the `default` VPC
61 * (Direct VPC egress) to reach the instance's private IP. Deployed from
62 * {@link ../Bindings.test.ts}.
63 */
64export default class RedisBindingsHost extends GCP.Function<RedisBindingsHost>()(
65 "RedisBindingsHost",
66 {
67 main: import.meta.url,
68 location: "us-central1",
69 invokerIamDisabled: true,
70 env: { GCP_TEST_SLOW: slow ? "1" : "" },
71 template: {
72 vpcAccess: {
73 egress: "PRIVATE_RANGES_ONLY",
74 networkInterfaces: [{ network: "default", subnetwork: "default" }],
75 },
76 },
77 },
78 Effect.gen(function* () {
79 const getAclPolicy = yield* GCP.Redis.GetAclPolicy(Acl);
80 const instance = slow ? yield* instanceProbes : {};
81
82 return {
83 fetch: serveProbes({
84 getAclPolicy: getAclPolicy(),
85 ...instance,
86 }),
87 };
88 }).pipe(
89 Effect.provide(GCP.Redis.GetAclPolicyHttp),
90 Effect.provide(GCP.Redis.GetInstanceHttp),
91 Effect.provide(GCP.Redis.GetAuthStringHttp),
92 Effect.provide(GCP.Redis.ReadRedisHttp),
93 Effect.provide(GCP.Redis.WriteRedisHttp),
94 Effect.provide(GCP.Redis.ReadWriteRedisHttp),
95 ),
96) {}