import { AbstractFactory, Container, DependencyRequirement, PropertyDependency, isInstantiable, DEPENDENCY_KEYS_METADATA_KEY, DEPENDENCY_KEYS_PROPERTY_METADATA_KEY, StaticInstantiable, FactoryProducer, } from '../../../di' import {Collection, ErrorWithContext} from '../../../util' import {Logging} from '../../../service/Logging' import {Config} from '../../../service/Config' import {Queue} from './Queue' import {SyncQueue} from './SyncQueue' /** * Dependency container factory that matches the abstract Queue token, but * produces an instance of whatever Queue driver is configured in the `server.queue.driver` config. */ @FactoryProducer() export class QueueFactory extends AbstractFactory { /** true if we have printed the synchronous queue driver warning once. */ private static loggedSyncQueueWarningOnce = false private di(): [Logging, Config] { return [ Container.getContainer().make(Logging), Container.getContainer().make(Config), ] } produce(): Queue { return new (this.getQueueClass())() } match(something: unknown): boolean { return something === Queue } getDependencyKeys(): Collection { const meta = Reflect.getMetadata(DEPENDENCY_KEYS_METADATA_KEY, this.getQueueClass()) if ( meta ) { return meta } return new Collection() } getInjectedProperties(): Collection { const meta = new Collection() let currentToken = this.getQueueClass() do { const loadedMeta = Reflect.getMetadata(DEPENDENCY_KEYS_PROPERTY_METADATA_KEY, currentToken) if ( loadedMeta ) { meta.concat(loadedMeta) } currentToken = Object.getPrototypeOf(currentToken) } while (Object.getPrototypeOf(currentToken) !== Function.prototype && Object.getPrototypeOf(currentToken) !== Object.prototype) return meta } /** * Get the configured queue driver and return some Instantiable. * @protected */ protected getQueueClass(): StaticInstantiable { const [logging, config] = this.di() const QueueClass = config.get('server.queue.driver', SyncQueue) if ( QueueClass === SyncQueue && !QueueFactory.loggedSyncQueueWarningOnce ) { logging.warn(`You are using the default synchronous queue driver. It is recommended you configure a background queue driver instead.`) QueueFactory.loggedSyncQueueWarningOnce = true } if ( !isInstantiable(QueueClass) || !(QueueClass.prototype instanceof Queue) ) { const e = new ErrorWithContext('Provided queue class does not extend from @extollo/lib.Queue') e.context = { configKey: 'server.queue.driver', class: QueueClass.toString(), } } return QueueClass } }