1import * as AWS from "alchemy/AWS";
2import * as Effect from "effect/Effect";
3import { HttpServerRequest } from "effect/http/HttpServerRequest";
4import * as HttpServerResponse from "effect/http/HttpServerResponse";
5import { EC2_MARKER } from "./ec2/marker.ts";
6import { PORTS } from "./ports.ts";
7
8/**
9 * A hosted **EC2 instance**: the fourth floci compute unit in the stack
10 * (after Lambda, the MicroVM, and ECS). Under `alchemy dev` the instance
11 * runs as a real docker container in the emulator — its userData boots the
12 * bundled program below — and floci publishes the security-group app port
13 * behind a host-routing mux, so the box answers at
14 * `http://<instanceId>.localhost.floci.io:<port>` on the developer's
15 * machine.
16 *
17 * Unlike the Workers/Lambda (sidecar hot swap) and ECS (image rebuild +
18 * container roll), the hosted instance reloads through the ENGINE: a
19 * content edit re-plans, the provider re-uploads the bundle in place and
20 * reboots the instance — same instance id, same address, new code.
21 */
22export default class Ec2Box extends AWS.EC2.Instance<Ec2Box>()(
23 "StressEc2Box",
24 Effect.gen(function* () {
25 const network = yield* AWS.EC2.Network("StressEc2Network", {
26 cidrBlock: "10.84.0.0/16",
27 availabilityZones: 1,
28 });
29 const securityGroup = yield* AWS.EC2.SecurityGroup("StressEc2Sg", {
30 vpcId: network.vpcId,
31 description: "dev-stress ec2 box",
32 ingress: [
33 {
34 ipProtocol: "tcp",
35 fromPort: PORTS.ec2,
36 toPort: PORTS.ec2,
37 cidrIpv4: "0.0.0.0/0",
38 description: "app",
39 },
40 ],
41 egress: [
42 {
43 ipProtocol: "-1",
44 cidrIpv4: "0.0.0.0/0",
45 description: "all outbound",
46 },
47 ],
48 });
49 return {
50 main: import.meta.filename,
51 imageId: AWS.EC2.amazonLinux2023(),
52 instanceType: "t3.micro",
53 subnetId: network.publicSubnetIds[0],
54 securityGroupIds: [securityGroup.groupId],
55 associatePublicIpAddress: true,
56 port: PORTS.ec2,
57 };
58 }),
59 Effect.gen(function* () {
60 return {
61 fetch: Effect.gen(function* () {
62 const request = yield* HttpServerRequest;
63 const url = new URL(request.url, "http://ec2-box");
64 if (url.pathname === "/marker") {
65 return yield* HttpServerResponse.json({ marker: EC2_MARKER });
66 }
67 return yield* HttpServerResponse.json({ ok: true });
68 }),
69 };
70 }),
71) {}