diff --git a/java-spring/accounts-query-side-backend/src/main/java/net/chrisrichardson/eventstore/javaexamples/banking/backend/queryside/accounts/AccountInfoUpdateService.java b/java-spring/accounts-query-side-backend/src/main/java/net/chrisrichardson/eventstore/javaexamples/banking/backend/queryside/accounts/AccountInfoUpdateService.java index ecc47fb..dca95c5 100644 --- a/java-spring/accounts-query-side-backend/src/main/java/net/chrisrichardson/eventstore/javaexamples/banking/backend/queryside/accounts/AccountInfoUpdateService.java +++ b/java-spring/accounts-query-side-backend/src/main/java/net/chrisrichardson/eventstore/javaexamples/banking/backend/queryside/accounts/AccountInfoUpdateService.java @@ -4,6 +4,7 @@ import com.mongodb.WriteResult; import net.chrisrichardson.eventstore.javaexamples.banking.common.accounts.AccountTransactionInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.dao.DuplicateKeyException; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Update; @@ -38,6 +39,9 @@ public class AccountInfoUpdateService { Collections.emptyList(), version)); logger.info("Saved in mongo"); + + } catch (DuplicateKeyException t) { + logger.warn("When saving ", t); } catch (Throwable t) { logger.error("Error during saving: "); logger.error("Error during saving: ", t); diff --git a/java-spring/accounts-query-side-backend/src/test/java/net/chrisrichardson/eventstore/javaexamples/banking/backend/queryside/accounts/AccountInfoUpdateServiceTest.java b/java-spring/accounts-query-side-backend/src/test/java/net/chrisrichardson/eventstore/javaexamples/banking/backend/queryside/accounts/AccountInfoUpdateServiceTest.java index 2b7baec..5643479 100644 --- a/java-spring/accounts-query-side-backend/src/test/java/net/chrisrichardson/eventstore/javaexamples/banking/backend/queryside/accounts/AccountInfoUpdateServiceTest.java +++ b/java-spring/accounts-query-side-backend/src/test/java/net/chrisrichardson/eventstore/javaexamples/banking/backend/queryside/accounts/AccountInfoUpdateServiceTest.java @@ -94,4 +94,20 @@ public class AccountInfoUpdateServiceTest { assertEquals(ti, accountInfo.getTransactions().get(0)); } + @Test + public void shouldHandleDuplicateSaveAccountInfo() throws ExecutionException, InterruptedException { + IdGenerator x = new IdGeneratorImpl(); + String accountId = x.genId().asString(); + String customerId = x.genId().asString(); + String version = x.genId().asString(); + + String title = "Checking account"; + BigDecimal initialBalance = new BigDecimal("1345"); + String description = "Some account"; + + accountInfoUpdateService.create(accountId, customerId, title, initialBalance, description, version); + accountInfoUpdateService.create(accountId, customerId, title, initialBalance, description, version); + + + } } \ No newline at end of file diff --git a/java-spring/customers-query-side-backend/src/main/java/net/chrisrichardson/eventstore/javaexamples/banking/backend/queryside/customers/CustomerInfoUpdateService.java b/java-spring/customers-query-side-backend/src/main/java/net/chrisrichardson/eventstore/javaexamples/banking/backend/queryside/customers/CustomerInfoUpdateService.java index fd70386..3964683 100644 --- a/java-spring/customers-query-side-backend/src/main/java/net/chrisrichardson/eventstore/javaexamples/banking/backend/queryside/customers/CustomerInfoUpdateService.java +++ b/java-spring/customers-query-side-backend/src/main/java/net/chrisrichardson/eventstore/javaexamples/banking/backend/queryside/customers/CustomerInfoUpdateService.java @@ -5,6 +5,7 @@ import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.Quer import net.chrisrichardson.eventstore.javaexamples.banking.common.customers.ToAccountInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.dao.DuplicateKeyException; import java.util.Collections; @@ -13,36 +14,38 @@ import java.util.Collections; */ public class CustomerInfoUpdateService { - private Logger logger = LoggerFactory.getLogger(getClass()); + private Logger logger = LoggerFactory.getLogger(getClass()); - private QuerySideCustomerRepository accountInfoRepository; + private QuerySideCustomerRepository querySideCustomerRepository; - public CustomerInfoUpdateService(QuerySideCustomerRepository accountInfoRepository) { - this.accountInfoRepository = accountInfoRepository; - } - - public void create(String id, CustomerInfo customerInfo) { - try { - accountInfoRepository.save(new QuerySideCustomer(id, - customerInfo.getName(), - customerInfo.getEmail(), - customerInfo.getSsn(), - customerInfo.getPhoneNumber(), - customerInfo.getAddress(), - Collections.emptyMap() - ) - ); - logger.info("Saved in mongo"); - } catch (Throwable t) { - logger.error("Error during saving: ", t); - throw new RuntimeException(t); + public CustomerInfoUpdateService(QuerySideCustomerRepository querySideCustomerRepository) { + this.querySideCustomerRepository = querySideCustomerRepository; } - } - public void addToAccount(String id, ToAccountInfo accountInfo) { - QuerySideCustomer customer = accountInfoRepository.findOne(id); - customer.getToAccounts().put(accountInfo.getId(), accountInfo); - accountInfoRepository.save(customer); - } + public void create(String id, CustomerInfo customerInfo) { + try { + querySideCustomerRepository.save(new QuerySideCustomer(id, + customerInfo.getName(), + customerInfo.getEmail(), + customerInfo.getSsn(), + customerInfo.getPhoneNumber(), + customerInfo.getAddress(), + Collections.emptyMap() + ) + ); + logger.info("Saved in mongo"); + } catch (DuplicateKeyException t) { + logger.warn("When saving ", t); + } catch (Throwable t) { + logger.error("Error during saving: ", t); + throw new RuntimeException(t); + } + } + + public void addToAccount(String id, ToAccountInfo accountInfo) { + QuerySideCustomer customer = querySideCustomerRepository.findOne(id); + customer.getToAccounts().put(accountInfo.getId(), accountInfo); + querySideCustomerRepository.save(customer); + } } diff --git a/java-spring/testutil/src/main/java/net/chrisrichardson/eventstorestore/javaexamples/testutil/TestUtil.java b/java-spring/testutil/src/main/java/net/chrisrichardson/eventstorestore/javaexamples/testutil/TestUtil.java index 025cdb1..2c84554 100644 --- a/java-spring/testutil/src/main/java/net/chrisrichardson/eventstorestore/javaexamples/testutil/TestUtil.java +++ b/java-spring/testutil/src/main/java/net/chrisrichardson/eventstorestore/javaexamples/testutil/TestUtil.java @@ -1,7 +1,5 @@ package net.chrisrichardson.eventstorestore.javaexamples.testutil; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; import rx.Observable; import rx.Subscriber; import rx.functions.Action1; @@ -13,7 +11,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import java.util.function.Supplier; public class TestUtil { @@ -25,18 +22,6 @@ public class TestUtil { } } - public static T awaitSuccessfulRequest(Supplier> func, Func1 predicate) { - try { - return Observable.interval(400, TimeUnit.MILLISECONDS) - .take(50) - .map(x -> func.get()) - .filter(re -> re.getStatusCode().equals(HttpStatus.OK) && re.getBody() != null && predicate.call(re.getBody())) - .toBlocking().first().getBody(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - static class Tuple2 { private A first; @@ -52,7 +37,7 @@ public class TestUtil { } - static class Success implements Outcome { + static class Success implements Outcome { T value; @@ -69,51 +54,26 @@ public class TestUtil { } } - public static void eventually(final Producer producer, final Verifier verifier) { - final int n = 150; - Object possibleException = Observable.timer(0, 200, TimeUnit.MILLISECONDS).flatMap(new Func1>>() { - - @Override - public Observable> call(Long aLong) { - try { - return fromCompletableFuture(producer.produce()).map(new Func1>() { - @Override - public Outcome call(T t) { - return new Success(t); - } - }); - } catch (Exception e) { - Outcome value = new Failure(e); - return Observable.just(value); - } + public static void eventually(Producer producer, Verifier predicate) { + Throwable laste = null; + for (int i = 0; i < 30 ; i++) { + try { + T x = producer.produce().get(30, TimeUnit.SECONDS); + predicate.verify(x); + return; + } catch (Throwable t) { + laste = t; } - }).map(new Func1, Throwable>() { - @Override - public Throwable call(Outcome t) { - try { - if (t instanceof Success) { - verifier.verify(((Success) t).value); - return null; - } else - return ((Failure) t).t; - } catch (Throwable e) { - return e; - } + try { + TimeUnit.SECONDS.sleep(1); + } catch (InterruptedException e) { + throw new RuntimeException(e); } - }).take(n).zipWith(Observable.range(0, n), new Func2>() { - @Override - public Tuple2 call(Throwable e, Integer idx) { - return new Tuple2(e, idx); - } - }).skipWhile(new Func1, Boolean>() { - @Override - public Boolean call(Tuple2 tuple2) { - return tuple2.first != null && tuple2.second < n - 1; - } - }).first().toBlocking().getIterator().next().first; - - if (possibleException != null) - throw new RuntimeException((Throwable) possibleException); + } + if (laste != null) + throw new RuntimeException("Last exception was", laste); + else + throw new RuntimeException("predicate never satisfied"); } private static Observable fromCompletableFuture(CompletableFuture future) {