···117117│ │ │ │
118118│ └──────────────────┘ │
119119│ │
120120-│ (No external dependencies) │
120120+│ ┌─────────────────────────────────┐ │
121121+│ │ InMemorySagaStateStore │ │
122122+│ │ - Map-based state storage │ │
123123+│ │ - Timeout-based lock expiry │ │
124124+│ │ - No external dependencies │ │
125125+│ └─────────────────────────────────┘ │
121126└─────────────────────────────────────┘
122127```
123128124129**Configuration:**
125130- `USE_IN_MEMORY_EVENTS=true`
126131- No Redis required
127127-- All processing in-memory
132132+- All processing in-memory with `InMemorySagaStateStore`
133133+- Uses `InMemoryEventWorkerProcess` for event handling
128134129135## Event Flow Example: CardAddedToLibrary
130136
+7-2
src/index.ts
···11import { configService } from './shared/infrastructure/config';
22import { AppProcess } from './shared/infrastructure/processes/AppProcess';
33import { FeedWorkerProcess } from './shared/infrastructure/processes/FeedWorkerProcess';
44+import { InMemoryEventWorkerProcess } from './shared/infrastructure/processes/InMemoryEventWorkerProcess';
4556async function main() {
67 const appProcess = new AppProcess(configService);
···89 // Start the app process
910 await appProcess.start();
10111111- // Start feed worker in the same process if using in-memory events
1212+ // Start appropriate worker based on event system type
1213 const useInMemoryEvents = process.env.USE_IN_MEMORY_EVENTS === 'true';
1314 if (useInMemoryEvents) {
1414- console.log('Starting feed worker in the same process...');
1515+ console.log('Starting in-memory event worker in the same process...');
1616+ const inMemoryWorkerProcess = new InMemoryEventWorkerProcess(configService);
1717+ await inMemoryWorkerProcess.start();
1818+ } else {
1919+ console.log('Starting BullMQ feed worker in the same process...');
1520 const feedWorkerProcess = new FeedWorkerProcess(configService);
1621 await feedWorkerProcess.start();
1722 }
···5151import { ATProtoIdentityResolutionService } from '../../../../modules/atproto/infrastructure/services/ATProtoIdentityResolutionService';
5252import { IIdentityResolutionService } from '../../../../modules/atproto/domain/services/IIdentityResolutionService';
5353import { CookieService } from '../services/CookieService';
5454+import { InMemorySagaStateStore } from '../../../../modules/feeds/infrastructure/InMemorySagaStateStore';
5555+import { RedisSagaStateStore } from '../../../../modules/feeds/infrastructure/RedisSagaStateStore';
54565557// Shared services needed by both web app and workers
5658export interface SharedServices {
···222224 };
223225 }
224226227227+ // Create saga with appropriate state store
228228+ let cardCollectionSaga: CardCollectionSaga;
229229+ if (useInMemoryEvents) {
230230+ const stateStore = new InMemorySagaStateStore();
231231+ cardCollectionSaga = new CardCollectionSaga(
232232+ sharedServices.feedService as any, // Will be properly typed when used
233233+ stateStore,
234234+ );
235235+ } else {
236236+ const stateStore = new RedisSagaStateStore(redisConnection!);
237237+ cardCollectionSaga = new CardCollectionSaga(
238238+ sharedServices.feedService as any, // Will be properly typed when used
239239+ stateStore,
240240+ );
241241+ }
242242+225243 return {
226244 ...sharedServices,
227245 redisConnection: redisConnection,
228246 eventPublisher,
229247 createEventSubscriber,
230230- cardCollectionSaga: null as any, // Will be created in worker process
248248+ cardCollectionSaga,
231249 };
232250 }
233251