Skip to content

Commit 19aa134

Browse files
committed
feat: s/redis/redpanda
Redis won't scale at real world scale for the ingestion pipeline, so we've replacing it with redpanda. We keep redis for caching.
1 parent 76631e5 commit 19aa134

File tree

24 files changed

+699
-388
lines changed

24 files changed

+699
-388
lines changed

.env.example

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,23 @@ LAT_WEAVIATE_GRPC_PORT=50051
6666
LAT_REDIS_HOST=localhost
6767
LAT_REDIS_PORT=6379
6868

69+
# Redpanda/Kafka Configuration
70+
LAT_KAFKA_BROKERS=localhost:9092
71+
LAT_KAFKA_CLIENT_ID=latitude-app
72+
# SECURITY: When SASL authentication is enabled (LAT_KAFKA_SASL_USERNAME/PASSWORD),
73+
# LAT_KAFKA_SSL must be set to true in production environments to prevent
74+
# transmitting credentials in plaintext.
75+
LAT_KAFKA_SSL=false
76+
# LAT_KAFKA_SASL_USERNAME=
77+
# LAT_KAFKA_SASL_PASSWORD=
78+
79+
# Consumer Configuration
80+
LAT_KAFKA_CONSUMER_GROUP_ID=latitude-event-processors-v1
81+
82+
# Topic Configuration
83+
LAT_KAFKA_EVENTS_TOPIC=domain-events
84+
LAT_KAFKA_DLQ_TOPIC=domain-events-dlq
85+
6986
# Object Storage
7087
LAT_STORAGE_DRIVER=fs
7188
# Absolute path in your laptop

.gitignore

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,3 @@ PRD.md
129129
progress.txt
130130

131131
packages/cli/prompts
132-
133-
.localstorage*
134-
docs/plans
135-
todos/
136-
compound-engineering.*
137-
138-
.mcp.json
139-
opencode.json

AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -888,7 +888,7 @@ Docker is used for local infrastructure services. Start them before running apps
888888

889889
```bash
890890
sudo dockerd &>/dev/null & # if Docker daemon not already running
891-
sudo docker compose up -d postgres clickhouse redis mailpit
891+
sudo docker compose up -d postgres clickhouse redis mailpit redpanda
892892
```
893893

894894
### Database setup

apps/workers/package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,11 @@
1313
"check:fix": "biome check --fix src"
1414
},
1515
"dependencies": {
16-
"@platform/cache-redis": "workspace:*",
1716
"@platform/db-postgres": "workspace:*",
1817
"@platform/events-outbox": "workspace:*",
19-
"@platform/queue-bullmq": "workspace:*",
18+
"@platform/queue-redpanda": "workspace:*",
2019
"@repo/observability": "workspace:*",
2120
"@types/pg": "catalog:",
22-
"bullmq": "catalog:",
2321
"dotenv": "catalog:",
2422
"effect": "catalog:",
2523
"pg": "catalog:",

apps/workers/src/clients.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,8 @@
1-
import type { RedisConnection } from "@platform/cache-redis"
2-
import { createRedisConnection } from "@platform/cache-redis"
31
import { createPostgresPool } from "@platform/db-postgres"
42
import type { Pool } from "pg"
53

6-
let redisConnectionInstance: RedisConnection | undefined
74
let pgPoolInstance: Pool | undefined
85

9-
export const getRedisConnection = (): RedisConnection => {
10-
if (!redisConnectionInstance) {
11-
redisConnectionInstance = createRedisConnection()
12-
}
13-
return redisConnectionInstance
14-
}
15-
166
export const getPostgresPool = (maxConnections?: number): Pool => {
177
if (!pgPoolInstance) {
188
pgPoolInstance = createPostgresPool(maxConnections ? { maxConnections } : undefined)

apps/workers/src/server.ts

Lines changed: 68 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
import { existsSync } from "node:fs"
22
import { fileURLToPath } from "node:url"
33
import { createPollingOutboxConsumer } from "@platform/events-outbox"
4-
import { createBullmqEventsPublisher } from "@platform/queue-bullmq"
4+
import {
5+
createKafkaClient,
6+
createRedpandaEventsConsumer,
7+
createRedpandaEventsPublisher,
8+
loadKafkaConfig,
9+
} from "@platform/queue-redpanda"
510
import { createLogger } from "@repo/observability"
611
import { config as loadDotenv } from "dotenv"
7-
import { getPostgresPool, getRedisConnection } from "./clients.ts"
8-
import { createEventsWorker } from "./workers/events.ts"
12+
import { Effect } from "effect"
13+
import { getPostgresPool } from "./clients.ts"
914

1015
const nodeEnv = process.env.NODE_ENV || "development"
1116
const envFilePath = fileURLToPath(new URL(`../../../.env.${nodeEnv}`, import.meta.url))
@@ -14,31 +19,75 @@ if (existsSync(envFilePath)) {
1419
loadDotenv({ path: envFilePath, quiet: true })
1520
}
1621

17-
const redisConnection = getRedisConnection()
1822
const pgPool = getPostgresPool(10)
19-
const { queue: eventsQueue, worker: eventsWorker } = createEventsWorker(redisConnection)
20-
const eventsPublisher = createBullmqEventsPublisher({ queue: eventsQueue })
21-
const outboxConsumer = createPollingOutboxConsumer(
22-
{
23-
pool: pgPool,
24-
pollIntervalMs: 1000,
25-
batchSize: 100,
26-
},
27-
eventsPublisher,
28-
)
2923

3024
const logger = createLogger("workers")
3125

32-
eventsWorker.on("ready", () => {
26+
// Simple event handler that logs events (placeholder for actual side effect processing)
27+
const eventHandler = {
28+
handle: (event: { id: string; event: { name: string; organizationId: string } }): Effect.Effect<
29+
void,
30+
unknown,
31+
never
32+
> =>
33+
Effect.gen(function* () {
34+
yield* Effect.logInfo(
35+
`Processing event ${event.id} of type ${event.event.name} for org ${event.event.organizationId}`,
36+
)
37+
}),
38+
}
39+
40+
// Initialize workers asynchronously
41+
const initializeWorkers = async () => {
42+
// Load Redpanda configuration
43+
const kafkaConfig = Effect.runSync(loadKafkaConfig())
44+
const kafkaClient = createKafkaClient(kafkaConfig)
45+
46+
// Create Redpanda publisher (async initialization)
47+
const eventsPublisher = await createRedpandaEventsPublisher({
48+
kafka: kafkaClient,
49+
config: kafkaConfig,
50+
})
51+
52+
// Create outbox consumer (polls Postgres outbox and publishes to Redpanda)
53+
const outboxConsumer = createPollingOutboxConsumer(
54+
{
55+
pool: pgPool,
56+
pollIntervalMs: 1000,
57+
batchSize: 100,
58+
},
59+
eventsPublisher,
60+
)
61+
62+
// Create Redpanda event consumer (consumes from Redpanda and processes events)
63+
const redpandaConsumer = createRedpandaEventsConsumer({
64+
kafka: kafkaClient,
65+
config: kafkaConfig,
66+
})
67+
68+
// Start consumers
3369
outboxConsumer.start()
70+
await redpandaConsumer.start(eventHandler)
71+
logger.info("workers ready - outbox consumer and Redpanda consumer started")
72+
73+
return { outboxConsumer, redpandaConsumer }
74+
}
3475

35-
logger.info("workers ready and outbox consumer started")
76+
const workersPromise = initializeWorkers().catch((error) => {
77+
logger.error("Failed to initialize workers", error)
78+
process.exit(1)
3679
})
3780

81+
// Graceful shutdown
3882
process.on("SIGINT", async () => {
39-
await outboxConsumer.stop()
83+
logger.info("shutting down workers...")
84+
try {
85+
const { outboxConsumer, redpandaConsumer } = await workersPromise
86+
await outboxConsumer.stop()
87+
await redpandaConsumer.stop()
88+
} catch (error) {
89+
logger.error("Error during shutdown (workers may not have started)", error)
90+
}
4091
await pgPool.end()
41-
await eventsQueue.close()
42-
await eventsWorker.close()
4392
process.exit(0)
4493
})

apps/workers/src/workers/events.ts

Lines changed: 0 additions & 19 deletions
This file was deleted.

docker-compose.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,45 @@ services:
4848
- "1025:1025"
4949
- "8025:8025"
5050

51+
redpanda:
52+
image: docker.redpanda.com/redpandadata/redpanda:v24.3.14
53+
command:
54+
- redpanda
55+
- start
56+
- --kafka-addr=internal://0.0.0.0:29092,external://0.0.0.0:9092
57+
- --advertise-kafka-addr=internal://redpanda:29092,external://localhost:9092
58+
- --mode=dev-container
59+
- --smp=1
60+
- --default-log-level=warn
61+
ports:
62+
- "9092:9092"
63+
volumes:
64+
- redpanda_data:/var/lib/redpanda/data
65+
healthcheck:
66+
test: ["CMD-SHELL", "rpk cluster health --brokers localhost:29092"]
67+
interval: 5s
68+
timeout: 10s
69+
retries: 12
70+
start_period: 15s
71+
72+
redpanda-init:
73+
image: docker.redpanda.com/redpandadata/redpanda:v24.3.14
74+
depends_on:
75+
redpanda:
76+
condition: service_healthy
77+
command:
78+
- rpk
79+
- topic
80+
- create
81+
- domain-events
82+
- domain-events-dlq
83+
- --brokers=redpanda:29092
84+
- --partitions=1
85+
- --replicas=1
86+
restart: "no"
87+
5188
volumes:
5289
postgres_data:
5390
clickhouse_data:
5491
weaviate-data:
92+
redpanda_data:

docs/auth.md

Lines changed: 0 additions & 108 deletions
This file was deleted.

0 commit comments

Comments
 (0)