Upgrade to Pro — share decks privately, control downloads, hide ads and more …

イベント駆動アーキテクチャ導入の手引きと共通の落とし穴 / Guide to Implementing Event-Driven Architecture and Common Pitfalls

nrs
June 16, 2024

イベント駆動アーキテクチャ導入の手引きと共通の落とし穴 / Guide to Implementing Event-Driven Architecture and Common Pitfalls

イベント駆動アーキテクチャにおける落とし穴についてお話しています。
こちらは JJUG CCC 2024 Spring の講演用資料です。

Code: https://github.com/nrslib/pubsubdoc

# URL
YouTube: https://www.youtube.com/c/narusemi
HomePage: https://nrslib.com
Twitter: https://twitter.com/nrslib

nrs

June 16, 2024
Tweet

More Decks by nrs

Other Decks in Programming

Transcript

  1. public record DocCreated( DocId docId, String body ) implements DocEvent

    { } { "docId": "uuid-toka-dayo", "body": "This is a document." }
  2. public record DocCreated( DocId docId, String text ) implements DocEvent

    { } { "docId": "uuid-toka-dayo", "body": "This is a document." }
  3. public record DocCreated( DocId docId, String text ) implements DocEvent

    { } { "docId": "uuid-toka-dayo", "body": "This is a document." }
  4. public record DocCreated( DocId docId, String text ) implements DocEvent

    { } { "docId": "uuid-toka-dayo", "body": "This is a document." }
  5. @EventHandler public void on(PaymentProcessRequested event) { if (event.paymentMethod() == PaymentMethod.CREDIT)

    { commandGateway.send( new CreditApply(event.paymentProcessId(), event.userId(), event.amount())); } } @EventHandler public void on(PaymentProcessRequested event) { if (event.paymentMethod() == PaymentMethod.BANK_TRANSFER) { var command = new TransferRequestCreate( event.paymentProcessId(), event.userId(), event.amount()); commandGateway.send(command) } }; @EventHandler public void on(PaymentProcessCompleted event) { commandGateway.send(new UserUpgrade(event.userId())); }
  6. @EventHandler public void on(PaymentProcessRequested event) { if (event.paymentMethod() == PaymentMethod.CREDIT)

    { commandGateway.send( new CreditApply(event.paymentProcessId(), event.userId(), event.amount())); } } @EventHandler public void on(PaymentProcessRequested event) { if (event.paymentMethod() == PaymentMethod.BANK_TRANSFER) { var command = new TransferRequestCreate( event.paymentProcessId(), event.userId(), event.amount()); commandGateway.send(command) } }; @EventHandler public void on(PaymentProcessCompleted event) { commandGateway.send(new UserUpgrade(event.userId())); }
  7. public record DocCreated( DocId docId, String text ) implements DocEvent

    { } { "docId": "uuid-toka-dayo", "body": "This is a document." }
  8. public class DocCreatedEvent1_to_2Upcaster extends SingleEventUpcaster { private static final SimpleSerializedType

    TARGET_TYPE = new SimpleSerializedType(DocCreated.class.getTypeName(), "1.0"); @Override protected boolean canUpcast(IntermediateEventRepresentation intermediateRepresentation) { return intermediateRepresentation.getType().equals(TARGET_TYPE); } @Override protected IntermediateEventRepresentation doUpcast( IntermediateEventRepresentation intermediateRepresentation ) { return intermediateRepresentation.upcastPayload( new SimpleSerializedType(TARGET_TYPE.getName(), "2.0"), com.fasterxml.jackson.databind.JsonNode.class, event -> { var node = (ObjectNode) event; var body = node.get("body").asText(); node.put("text", body); return node; } ); } }
  9. @EventHandler public void on(PaymentProcessRequested event) { if (event.paymentMethod() == PaymentMethod.CREDIT)

    { commandGateway.send( new CreditApply(event.paymentProcessId(), event.userId(), event.amount())); } } @EventHandler public void on(PaymentProcessRequested event) { if (event.paymentMethod() == PaymentMethod.BANK_TRANSFER) { var command = new TransferRequestCreate( event.paymentProcessId(), event.userId(), event.amount()); commandGateway.send(command) } }; @EventHandler public void on(PaymentProcessCompleted event) { commandGateway.send(new UserUpgrade(event.userId())); }
  10. @Component public class DocProjection { private final DocRepository repository; @ResetHandler

    public void reset() { this.repository.deleteAll(); } @EventHandler public void on(DocCreated event) { var doc = new DocDataModel(); doc.setDocId(event.docId().asString()); doc.setBody(event.body()); repository.save(doc); } @EventHandler public void on(DocUpdated event) { var doc = repository.findById(event.docId().asString()).orElseThrow(); doc.setBody(event.body()); repository.save(doc); } ... }
  11. @Operation(summary = "Test.") @PostMapping public Mono<SyncPostResponse> post() { var requestId

    = UUID.randomUUID(); var query = new FindAsyncResponse(requestId); var result = queryGateway.subscriptionQuery( query, ResponseTypes.instanceOf(FindAsyncResponseResult.class), ResponseTypes.instanceOf(FindAsyncResponseResult.class)); var command = new StartCommunication(requestId, "Hello, world! @" + LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); commandGateway.sendAndWait(command); return Mono.from(result.updates() .filter(update -> update.data() != null) .next() .map(updateResult -> new SyncPostResponse(requestId, updateResult.data())) .timeout(Duration.ofSeconds(10)) .onErrorResume(Mono::error) .doFinally(signalType -> result.close()) ); }
  12. @Operation(summary = "Test.") @PostMapping public Mono<SyncPostResponse> post() { var requestId

    = UUID.randomUUID(); var query = new FindAsyncResponse(requestId); var result = queryGateway.subscriptionQuery( query, ResponseTypes.instanceOf(FindAsyncResponseResult.class), ResponseTypes.instanceOf(FindAsyncResponseResult.class)); var command = new StartCommunication(requestId, "Hello, world! @" + LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); commandGateway.sendAndWait(command); return Mono.from(result.updates() .filter(update -> update.data() != null) .next() .map(updateResult -> new SyncPostResponse(requestId, updateResult.data())) .timeout(Duration.ofSeconds(10)) .onErrorResume(Mono::error) .doFinally(signalType -> result.close()) ); }
  13. @Operation(summary = "Test.") @PostMapping public Mono<SyncPostResponse> post() { var requestId

    = UUID.randomUUID(); var query = new FindAsyncResponse(requestId); var result = queryGateway.subscriptionQuery( query, ResponseTypes.instanceOf(FindAsyncResponseResult.class), ResponseTypes.instanceOf(FindAsyncResponseResult.class)); var command = new StartCommunication(requestId, "Hello, world! @" + LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); commandGateway.sendAndWait(command); return Mono.from(result.updates() .filter(update -> update.data() != null) .next() .map(updateResult -> new SyncPostResponse(requestId, updateResult.data())) .timeout(Duration.ofSeconds(10)) .onErrorResume(Mono::error) .doFinally(signalType -> result.close()) ); }
  14. @Operation(summary = "Test.") @PostMapping public Mono<SyncPostResponse> post() { var requestId

    = UUID.randomUUID(); var query = new FindAsyncResponse(requestId); var result = queryGateway.subscriptionQuery( query, ResponseTypes.instanceOf(FindAsyncResponseResult.class), ResponseTypes.instanceOf(FindAsyncResponseResult.class)); var command = new StartCommunication(requestId, "Hello, world! @" + LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); commandGateway.sendAndWait(command); return Mono.from(result.updates() .filter(update -> update.data() != null) .next() .map(updateResult -> new SyncPostResponse(requestId, updateResult.data())) .timeout(Duration.ofSeconds(10)) .onErrorResume(Mono::error) .doFinally(signalType -> result.close()) ); }
  15. @Component public record PaymentProcessTransferRequestStep(CommandGateway commandGateway) { @EventHandler public void on(PaymentProcessRequested

    event) { if (event.paymentMethod() == PaymentMethod.BANK_TRANSFER) { var command = new TransferRequestCreate( event.paymentProcessId(), event.userId(), event.amount()); commandGateway.send(command); } } }
  16. @Aggregate public class TransferRequestAggregate extends AbstractAggregate<TransferRequest, TransferRequestId, TransferRequestEvent> { ...

    @CommandHandler public TransferRequestAggregate(TransferRequestCreate command) { var event = TransferRequest.create(new TransferRequestId()); apply(event); } }
  17. @Component public record TransferRequestProjection(TransferRequestRepository repository) { @ResetHandler public void reset()

    { repository.deleteAll(); } @EventHandler public void on(TransferRequestStarted event) { var data = new TransferRequestDataModel(); data.setTransferRequestId(event.transferRequestId().asString()); data.setStatus(TransferRequestStatus.CREATED); repository.save(data); } }