stemmlerjs / ddd-forum

Hacker news-inspired forum app built with TypeScript using DDD practices from solidbook.io.
https://dddforum.com
ISC License
1.95k stars 441 forks source link

Atomically send event and update the database `outbox pattern` #125

Open pbell23 opened 10 months ago

pbell23 commented 10 months ago

In some parts of the code, like this one : ddd-forum/src/modules/users/useCases/createUser/CreateUserUseCase.ts :

const userOrError: Result<User> = User.create({
        email, password, username,
      });

      if (userOrError.isFailure) {
        return left(
          Result.fail<User>(userOrError.getErrorValue().toString())
        ) as Response;
      }

      const user: User = userOrError.getValue();

      await this.userRepo.save(user);

      return right(Result.ok<void>())

    } catch (err) {
      return left(new AppError.UnexpectedError(err)) as Response;
    }

we both need to send a domain event (here User.create will dispatch a UserCreated event) and update the database (here, await this.userRepo.save(user);). But these operations need to be atomic to avoid inconsistencies. In this example, once UserCreated is dispatched, it is then listened by the forum module which will create a new member based on this event. This means that if this database persist operation fails :

await this.userRepo.save(user);

we will have a member created without its associated user.

To avoid that, the outbox pattern must be implemented. Here is a reference explaining the problem and the solution : https://microservices.io/patterns/data/transactional-outbox.html .

What do you think ?