A social knowledge tool for researchers built on ATProto
45
fork

Configure Feed

Select the types of activity you want to include in your feed.

cleaning up composite root setup

+34 -29
+4 -2
src/modules/cards/application/useCases/commands/AddCardToCollectionUseCase.ts
··· 28 28 29 29 export class AddCardToCollectionUseCase extends BaseUseCase< 30 30 AddCardToCollectionDTO, 31 - Result<AddCardToCollectionResponseDTO, ValidationError | AppError.UnexpectedError> 31 + Result< 32 + AddCardToCollectionResponseDTO, 33 + ValidationError | AppError.UnexpectedError 34 + > 32 35 > { 33 36 constructor( 34 37 private cardRepository: ICardRepository, 35 - private collectionRepository: ICollectionRepository, 36 38 private cardCollectionService: CardCollectionService, 37 39 eventPublisher: IEventPublisher, 38 40 ) {
+21 -17
src/shared/infrastructure/http/factories/ServiceFactory.ts
··· 43 43 import { IEventPublisher } from '../../../application/events/IEventPublisher'; 44 44 import { QueueName } from '../../events/QueueConfig'; 45 45 import { RedisFactory } from '../../redis/RedisFactory'; 46 + import { IEventSubscriber } from 'src/shared/application/events/IEventSubscriber'; 46 47 47 48 // Shared services needed by both web app and workers 48 49 export interface SharedServices { ··· 63 64 cardLibraryService: CardLibraryService; 64 65 cardCollectionService: CardCollectionService; 65 66 authMiddleware: AuthMiddleware; 66 - eventPublisher?: IEventPublisher; 67 + eventPublisher: IEventPublisher; 67 68 } 68 69 69 70 // Worker specific services (includes subscribers) 70 71 export interface WorkerServices extends SharedServices { 71 72 redisConnection: Redis; 72 73 eventPublisher: IEventPublisher; 73 - createEventSubscriber: (queueName: QueueName) => BullMQEventSubscriber; 74 + createEventSubscriber: (queueName: QueueName) => IEventSubscriber; 74 75 } 75 76 76 77 // Legacy interface for backward compatibility ··· 88 89 configService: EnvironmentConfigService, 89 90 repositories: Repositories, 90 91 ): WebAppServices { 91 - const sharedServices = this.createSharedServices(configService, repositories); 92 - 92 + const sharedServices = this.createSharedServices( 93 + configService, 94 + repositories, 95 + ); 96 + 93 97 const useMockAuth = process.env.USE_MOCK_AUTH === 'true'; 94 98 95 99 // OAuth Client (always create for real, but may not be used if mocking) ··· 137 141 138 142 const authMiddleware = new AuthMiddleware(sharedServices.tokenService); 139 143 140 - // Optionally create event publisher for web app if Redis is available 141 - let eventPublisher: IEventPublisher | undefined; 142 - if (process.env.REDIS_URL && !process.env.USE_FAKE_PUBLISHERS) { 143 - try { 144 - const redisConnection = RedisFactory.createConnection(); 145 - eventPublisher = new BullMQEventPublisher(redisConnection); 146 - } catch (error) { 147 - console.warn('Failed to create Redis connection for event publisher:', error); 148 - } 149 - } 144 + const redisConnection = RedisFactory.createConnection( 145 + configService.getWorkersConfig().redisUrl, 146 + ); 147 + const eventPublisher = new BullMQEventPublisher(redisConnection); 150 148 151 149 return { 152 150 ...sharedServices, ··· 166 164 configService: EnvironmentConfigService, 167 165 repositories: Repositories, 168 166 ): WorkerServices { 169 - const sharedServices = this.createSharedServices(configService, repositories); 167 + const sharedServices = this.createSharedServices( 168 + configService, 169 + repositories, 170 + ); 170 171 171 172 // Redis connection is required for workers 172 173 if (!process.env.REDIS_URL) { 173 - throw new Error('REDIS_URL environment variable is required for worker services'); 174 + throw new Error( 175 + 'REDIS_URL environment variable is required for worker services', 176 + ); 174 177 } 175 178 176 - const redisConnection = RedisFactory.createConnection(); 179 + const redisUrl = configService.getWorkersConfig().redisUrl; 180 + const redisConnection = RedisFactory.createConnection(redisUrl); 177 181 178 182 const eventPublisher = new BullMQEventPublisher(redisConnection); 179 183
+3
src/shared/infrastructure/http/factories/UseCaseFactory.ts
··· 81 81 services.metadataService, 82 82 services.cardLibraryService, 83 83 services.cardCollectionService, 84 + services.eventPublisher, 84 85 ), 85 86 addCardToLibraryUseCase: new AddCardToLibraryUseCase( 86 87 repositories.cardRepository, ··· 90 91 addCardToCollectionUseCase: new AddCardToCollectionUseCase( 91 92 repositories.cardRepository, 92 93 services.cardCollectionService, 94 + services.eventPublisher, 93 95 ), 94 96 updateNoteCardUseCase: new UpdateNoteCardUseCase( 95 97 repositories.cardRepository, ··· 121 123 createCollectionUseCase: new CreateCollectionUseCase( 122 124 repositories.collectionRepository, 123 125 services.collectionPublisher, 126 + services.eventPublisher, 124 127 ), 125 128 updateCollectionUseCase: new UpdateCollectionUseCase( 126 129 repositories.collectionRepository,
+6 -10
src/shared/infrastructure/redis/RedisFactory.ts
··· 1 1 import Redis from 'ioredis'; 2 2 3 3 export class RedisFactory { 4 - static createConnection(redisUrl?: string): Redis { 5 - const url = redisUrl || process.env.REDIS_URL || 'redis://localhost:6379'; 6 - 7 - return new Redis(url, { 8 - maxRetriesPerRequest: 3, 9 - lazyConnect: true, 10 - retryDelayOnFailover: 100, 11 - enableReadyCheck: false, 12 - maxRetriesPerRequest: null, 13 - }); 4 + private static instance: Redis | null = null; 5 + static createConnection(redisUrl: string): Redis { 6 + if (!this.instance) { 7 + this.instance = new Redis(redisUrl); 8 + } 9 + return this.instance; 14 10 } 15 11 }