首页 > 解决方案 > When using nested subscribers app will crash (NestJs+TypeOrm+Mysql)

问题描述

I have 1 controller, 3 services and 2 subscribers for service 1 and 2. when subscriber 2 will call create method of service 3, app will be stuck at loopback

flow:

OrmConfig:

const config: MysqlConnectionOptions = {
    type: 'mysql',
    host: 'localhost',
    port: 3306,
    username: 'root',
    password: 'secret',
    database: 'db_name',
    entities: ['dist/**/entities/*.entity{.ts,.js}'],
    subscribers: ['dist/**/subscribers/*.subscriber{.ts,.js}'],
    synchronize: false,
    connectTimeout: 1500,
    extra: {
        connectionLimit: 20,
    },
};

Controller:

@Contoller('order')
export class bankActionsControllerV1 {
    constructor(private readonly bankActionsService: BankActionsService) {}

    @Post('transfer')
    async doTransferBankAction(@Body() body) {
        return await this.bankActionsService.create({...body});
    }
}

service 1:

@Injectable()
export class BankActionsService {
    constructor(@InjectRepository(BankAction) private readonly bankActionsRepository: Repository<BankAction>) {}

    public async create(data: CreateBankActionDto, additionalData?: ObjectLiteral): Promise<BankAction> {
        const newBankAction = this.bankActionsRepository.create(data);
        return await this.bankActionsRepository.save(newBankAction, { data: additionalData });
    }
}

subscriber 1:

@Injectable()
export class BankActionsSubscriber implements EntitySubscriberInterface<BankAction> {
    constructor(connection: Connection, @Inject(OrdersService) private readonly ordersService: OrdersService) {
        connection.subscribers.push(this);
    }

    listenTo = () => BankAction;

    async afterInsert(event: InsertEvent<BankAction>) {
        return await this.ordersService.create(example_data); // <= service 2
    }
}

service 2:

@Injectable()
export class OrdersService {
    constructor(@InjectRepository(Order) private readonly ordersRepository: Repository<Order>) {}
    public async create(data: CreateOrderDto): Promise<Order> {
        const newOrder = this.ordersRepository.create(data);
        return await this.ordersRepository.save(newOrder);
    }
}

subscriber 2:

@Injectable()
export class OrdersSubscriber implements EntitySubscriberInterface<Order> {
    constructor(connection: Connection, @Inject(TransactionsService) private readonly transactionsService: TransactionsService) {
        connection.subscribers.push(this);
    }

    listenTo = () => Order;

    async afterInsert(event: InsertEvent<Order>) {
        return await this.transactionsService.create(example_data); // <= start crash
    }
}

service 3:

@Injectable()
export class TransactionsService {
    constructor(@InjectRepository(Transaction) private readonly transactionsRepository: Repository<Transaction>) {}

    public async create(data: CreateTransactionDto): Promise<Transaction> {
        const newTransaction = this.transactionsRepository.create(data);
        return await this.transactionsRepository.save(newTransaction); // <= crash here
    }
}

MySQL logs:

2021-11-16T13:28:41.099845Z   381 Connect   root@172.18.0.1 on loyalty using TCP/IP
2021-11-16T13:28:41.144343Z   381 Query START TRANSACTION
2021-11-16T13:28:41.151288Z   381 Query INSERT INTO `bank_actions`(`id`, `author_id`, `merchant_id`, `customer_id`, `title`, `subtitle`, `description`, `type`, `uuid`, `extra`, `created_at`, `updated_at`) VALUES (DEFAULT, '3671', '45', '3671', DEFAULT, DEFAULT, DEFAULT, 'transfer', 'bc45980f-fef2-4b5a-b9be-cbb3d07600c5', '{\"amount\":1100,\"source\":\"7309877115803689\",\"destination\":\"8664825723794189\"}', '2021-11-16 16:58:41.000', '2021-11-16 16:58:41.000')
2021-11-16T13:28:41.160903Z   380 Query START TRANSACTION
2021-11-16T13:28:41.162365Z   380 Query INSERT INTO `orders`(`id`, `from_account_id`, `to_account_id`, `amount`, `UID`, `goods_id`, `goods_type`, `order_payment_id`, `settlement_id`, `campaign_id`, `author_id`, `merchant_id`, `campaign_calculate`, `from_treasury_account_id`, `to_treasury_account_id`, `paid_at`, `refund`, `cash_out`, `type`, `extra_values`, `credited_at`, `debited_at`, `created_at`, `updated_at`) VALUES (DEFAULT, '515723', '515722', 1100, '16370693219277f0c3a209', '151', 'BankAction', DEFAULT, DEFAULT, DEFAULT, '3671', '45', 0, '435491', '435491', DEFAULT, DEFAULT, DEFAULT, 'iran_khodro_bank_action_transfer_order_nested', '{\"for\":null,\"description\":null}', DEFAULT, DEFAULT, '2021-11-16 16:58:41.000', '2021-11-16 16:58:41.000')
2021-11-16T13:28:41.167351Z   382 Connect   root@172.18.0.1 on loyalty using TCP/IP
2021-11-16T13:28:41.167577Z   382 Query START TRANSACTION
2021-11-16T13:28:41.168253Z   382 Query INSERT INTO `transactions`(`id`, `from_account_id`, `to_account_id`, `order_id`, `amount`, `split`, `reverse`, `revoked`, `created_at`, `updated_at`) VALUES (DEFAULT, '515723', '435491', '110687', 1100, DEFAULT, DEFAULT, DEFAULT, '2021-11-16 16:58:41.000', '2021-11-16 16:58:41.000')

标签: nestjstypeormmysql2subscriber

解决方案


推荐阅读