Unable to load Aggregate using Repository.load() for Integer AggregateIdentifier - repository

I've been trying in vain to load an aggregate using the load method of the repository class. I know that the load() method requires a string argument but my aggregate identifier is integer.
I have tried to convert to string, yet I'm not able to load the aggregate. I keep getting null.
My code is shown below
#Autowired
private Repository<Product> repository;
#CommandHandler
public Order(CreateOrderCommand cmd){
try{
//This line throws an error
Product product = (Product) repository.load(Integer.toString(cmd.getProductId()));
}
catch (Exception ex){
System.out.println("Oops! Error Occured: " + ex.getMessage());
}
apply(
new OrderCreatedEvent(
cmd.getOrderId(), cmd.getPrice(), cmd.getNumber(), cmd.getProductId()
)
);
}
I'm providing an more updates:
I simply want to update the products stock, when a new order is placed. So what I did was that in the CommandHandler for creating a new Order, I simply find the Product aggregate and call it's UpdateStock method, which is a command handler.
Is there something I really don't understand?
These are the files below:
The Product aggregate:
#Aggregate
public class Product {
#AggregateIdentifier
private String id;
private Double price;
private Integer stock;
private String description;
public Product() {
}
#CommandHandler
public Product(AddProductCommand cmd){
apply( new ProductAddedEvent(
cmd.getId(),
cmd.getPrice(),
cmd.getStock(),
cmd.getDescription()
)
);
}
#CommandHandler
public void updateStock (UpdateStockCommand cmd){
if(this.stock >= cmd.getStock()){
apply(new StockUpdatedEvent(cmd.getId(), cmd.getStock()));
}
else {
throw new RuntimeException("Out of Stock!");
}
}
#EventSourcingHandler
public void on(StockUpdatedEvent evt){
id = evt.getId();
stock = stock - evt.getStock();
}
#EventSourcingHandler
public void on(ProductAddedEvent evt){
id = evt.getId();
price = evt.getPrice();
stock = evt.getStock();
description = evt.getDescription();
}
}
The Order aggregate:
#Aggregate
public class Order {
#AggregateIdentifier
private String orderId;
private Double price;
private Integer number;
private String productId;
//Repository provides an abstraction for storage of Aggregates
#Autowired
private Repository<Product> repository;
#CommandHandler
public Order(CreateOrderCommand cmd){
try{
//This line throws an error
Product product = (Product) repository.load(cmd.getProductId());
}
catch (Exception ex){
System.out.println("Oops! Error Occured: " + ex.getMessage());
}
apply(
new OrderCreatedEvent(
cmd.getOrderId(), cmd.getPrice(), cmd.getNumber(), cmd.getProductId()
)
);
}
#EventSourcingHandler
public void on(OrderCreatedEvent evt){
orderId = evt.getOrderId();
price = evt.getPrice();
number = evt.getNumber();
productId = evt.getProductId();
}
}

As you have noticed, Axon will enforce a String for the aggregate identifier. This doesn't mean you need to provide a String directly. It'll work perfectly fine as long as you have a sensible toString() method implemented. Hence, using Integer as the aggregate identifier will result in the toString() result of that field to be used as the aggregate identifier.
Having said that, I'm surprised you are unable to load an aggregate based on this.
Maybe we need to do some follow up based on that, but firstly I want to comment on the snippet you're sharing.
It seems like you have a constructor command handler on the Order class. Moreover, that signals to me that the Order class is an aggregate.
I'd like to state that by no means would I ever recommend to load in an Aggregate from within another Aggregate.
Doing so ties in the lock on the Order aggregate with the Product aggregate, thus blocking a larger portion of your system than the sender of CreateOrderCommand would ever expect.
Communication between aggregate should be kept asynchronous at all times, through means of event messages.
That thus requires a dedicated Event Handling Component which does the coordination between both instances based on the published event.
I'd thus strongly suggest a rewrite of your logic on the matter.
When it comes to loading in an aggregate, I'd be hard pressed to give you a reasoning right now.
Hence, let me ask a couple of follow up questions.
I'd suggest to update your original request with the responses by the way; to maintain a nice thread of continuity.
Which version of Axon are you using any way?
Are you using any interesting configurations around the Product aggregate?
Are you pairing your application with Axon Server? If so, standard or enterprise, and which version?
Do you use the Configuration API directly or the axon-spring-boot-starter?
Update
Thanks for updating your question Kindson, let me update my answer too.
Firstly, as I already stated previously, I would never load in an Aggregate from within another Aggregate. Both your Order class and Product class are Aggregates and the snippets make overly clear that you are consolidating the "product Repository" from within the Order aggregate.
This approach does not only prolong locks on your aggregates, thus imposing strains on your users, but following this approach might event incur deadlocks. As a rule of thumb, always follow an asynchronous approach to communicating between aggregate instances. Thus a component reacting on an aggregate's events and dispatching commands to another. This can be done in a regular Event Handling Component, or a Saga for example.
Apart from the above, I have tested locally whether I could use an Integer as an Aggregate Identifier. Thus, as the #AggregateIdentifier annotated field in the aggregate and as the #TargetAggregateIdentifier annotated field on your command message. On top of that, I tried this out by having the framework call the Repository#load(String) operation (thus just dispatching a command on the CommandGateway/CommandBus) and by calling it directly as you did.
Sadly, this works out fine for me. Thus, as another follow up, I'd suggest to share the actual exception you are getting when you are performing the Repository#load(String) operation.

Related

How to repeat Mono while not empty

I have a method which returns like this!
Mono<Integer> getNumberFromSomewhere();
I need to keep calling this until it has no more items to emit. That is I need to make this as Flux<Integer>.
One option is to add repeat. the point is - I want to stop when the above method emits the first empty signal.
Is there any way to do this? I am looking for a clean way.
A built-in operator that does that (although it is intended for "deeper" nesting) is expand.
expand naturally stops expansion when the returned Publisher completes empty.
You could apply it to your use-case like this:
//this changes each time one subscribes to it
Mono<Integer> monoWithUnderlyingState;
Flux<Integer> repeated = monoWithUnderlyingState
.expand(i -> monoWithUnderlyingState);
I'm not aware of a built-in operator which would do the job straightaway. However, it can be done using a wrapper class and a mix of operators:
Flux<Integer> repeatUntilEmpty() {
return getNumberFromSomewhere()
.map(ResultWrapper::new)
.defaultIfEmpty(ResultWrapper.EMPTY)
.repeat()
.takeWhile(ResultWrapper::isNotEmpty)
}
// helper class, not necessarily needs to be Java record
record ResultWrapper(Integer value) {
public static final ResultWrapper EMPTY = new ResultWrapper(null);
public boolean isNotEmpty() {
return value != null;
}
}

Spring Cloud Stream deserialization error handling for Batch processing

I have a question about handling deserialization exceptions in Spring Cloud Stream while processing batches (i.e. batch-mode: true).
Per the documentation here, https://docs.spring.io/spring-kafka/docs/2.5.12.RELEASE/reference/html/#error-handling-deserializer, (looking at the implementation of FailedFooProvider), it looks like this function should return a subclass of the original message.
Is the intent here that a list of both Foo's and BadFoo's will end up at the original #StreamListener method, and then it will be up to the code (i.e. me) to sort them out and handle separately? I suspect this is the case, as I've read that the automated DLQ sending isn't desirable for batch error handling, as it would resubmit the whole batch.
And if this is the case, what if there is more than one message type received by the app via different #StreamListener's, say Foo's and Bar's. What type should the value function return in that case? Below is the pseudo code to illustrate the second question?
#StreamListener
public void readFoos(List<Foo> foos) {
List<> badFoos = foos.stream()
.filter(f -> f instanceof BadFoo)
.map(f -> (BadFoo) f)
.collect(Collectors.toList());
// logic
}
#StreamListener
public void readBars(List<Bar> bars) {
// logic
}
// Updated to return Object and let apply() determine subclass
public class FailedFooProvider implements Function<FailedDeserializationInfo, Object> {
#Override
public Object apply(FailedDeserializationInfo info) {
if (info.getTopics().equals("foo-topic") {
return new BadFoo(info);
}
else if (info.getTopics().equals("bar-topic") {
return new BadBar(info);
}
}
}
Yes, the list will contain the function result for failed deserializations; the application needs to handle them.
The function needs to return the same type that would have been returned by a successful deserialization.
You can't use conditions with batch listeners. If the list has a mixture of Foos and Bars, they all go to the same listener.

How to properly return status/error codes from an Azure Function that was triggered by an Event Grid event

I'm trying to wrap my head around how to manage controlled and uncontrolled results/failures in Azure Functions triggered by Event Grid events. I'm sure I'm missing some fundamental aspect but I can't really make sense of the available Microsoft documentation.
Using the current Visual Studio 2019 Azure Function templates for Event Grid triggers, we get C# methods that looks similar to this:
[FunctionName("UserCreated")]
public static void UserCreated([EventGridTrigger]EventGridEvent evt, ILogger log)
{
...
}
Q1. What is the proper way of returning statuses and error codes from these methods so that the event can be either retried or passed to the dead letter blob? Lets say I want to return a Status 400 Bad Request because the custom data payload in the event that was passed in wasn't up to speed. I've tried this:
[FunctionName("UserCreated")]
public static async Task<IActionResult> UserCreated([EventGridTrigger]EventGridEvent evt, ILogger log)
{
...
return new BadRequestObjectResult("ouch");
}
... which just results in this error when running the function locally:
Cannot bind parameter '$return' to type IActionResult&. Make sure the parameter Type is supported by the binding.
I don't understand this error and have no idea how to solve it.
Q2. How do we properly catch exceptions and return them in an orderly fashion? Let's say the UserCreated method above requires the passed in event to have a few custom datapoints, and that one of those datapoints are missing. E.g. we have this:
[JsonObject(ItemRequired = Required.Always)]
private class CustomerAndContactIds
{
public int CustomerId { get; set; }
public int ContactId { get; set; }
}
... and when we convert some event data that is missing e.g. the ContactID field, like so:
private static T ExtractCustomPayloadFromEvent<T>(EventGridEvent evt)
{
return JObject.FromObject(evt.Data).ToObject<T>();
}
... we get this in the logs:
System.Private.CoreLib: Exception while executing function: UserCreated. Newtonsoft.Json: Required property 'ContactPersonId' not found in JSON. Path ''.
However, all we get in e.g. Postman is:
Exception while executing function: UserCreated
What's the proper way of making this a bit more legible for consumers that aren't privy to e.g. the Azure log stream or Azure Insights?
To Q1:
Currently version of the EventGridTrigger function doesn't have a specific exception object to handle for its wrapper back a HttpStatusCode value. In other words, any exception in the azure function will force a retry pattern when it is enabled.
As a workaround for this issue, we can use a HttpTrigger function for subscriber handler with the HttpStatusCode return value.

Optaplanner: NullPointerException when calling scoreDirector.beforeVariableChanged in a simple custom move

I am building a Capacited Vehicle Routing Problem with Time Windows, but with one small difference when compared to the one provided in examples from the documentation: I don't have a depot. Instead, each order has a pickup step, and a delivery step, in two different locations.
(like in the Vehicle Routing example from the documentation, the previousStep planning variable has the CHAINED graph type, and its valueRangeProviderRefs includes both Drivers, and Steps)
This difference adds a couple of constraints:
the pickup and delivery steps of a given order must be handled by the same driver
the pickup must be before the delivery
After experimenting with constraints, I have found that it would be more efficient to implement two types of custom moves:
assign both steps of an order to a driver
rearrange the steps of a driver
I am currently implementing that first custom move. My solver's configuration looks like this:
SolverFactory<RoutingProblem> solverFactory = SolverFactory.create(
new SolverConfig()
.withSolutionClass(RoutingProblem.class)
.withEntityClasses(Step.class, StepList.class)
.withScoreDirectorFactory(new ScoreDirectorFactoryConfig()
.withConstraintProviderClass(Constraints.class)
)
.withTerminationConfig(new TerminationConfig()
.withSecondsSpentLimit(60L)
)
.withPhaseList(List.of(
new LocalSearchPhaseConfig()
.withMoveSelectorConfig(CustomMoveListFactory.getConfig())
))
);
My CustomMoveListFactory looks like this (I plan on migrating it to an MoveIteratorFactory later, but for the moment, this is easier to read and write):
public class CustomMoveListFactory implements MoveListFactory<RoutingProblem> {
public static MoveListFactoryConfig getConfig() {
MoveListFactoryConfig result = new MoveListFactoryConfig();
result.setMoveListFactoryClass(CustomMoveListFactory.class);
return result;
}
#Override
public List<? extends Move<RoutingProblem>> createMoveList(RoutingProblem routingProblem) {
List<Move<RoutingProblem>> moves = new ArrayList<>();
// 1. Assign moves
for (Order order : routingProblem.getOrders()) {
Driver currentDriver = order.getDriver();
for (Driver driver : routingProblem.getDrivers()) {
if (!driver.equals(currentDriver)) {
moves.add(new AssignMove(order, driver));
}
}
}
// 2. Rearrange moves
// TODO
return moves;
}
}
And finally, the move itself looks like this (nevermind the undo or the isDoable for the moment):
#Override
protected void doMoveOnGenuineVariables(ScoreDirector<RoutingProblem> scoreDirector) {
assignStep(scoreDirector, order.getPickupStep());
assignStep(scoreDirector, order.getDeliveryStep());
}
private void assignStep(ScoreDirector<RoutingProblem> scoreDirector, Step step) {
StepList beforeStep = step.getPreviousStep();
Step afterStep = step.getNextStep();
// 1. Insert step at the end of the driver's step list
StepList lastStep = driver.getLastStep();
scoreDirector.beforeVariableChanged(step, "previousStep"); // NullPointerException here
step.setPreviousStep(lastStep);
scoreDirector.afterVariableChanged(step, "previousStep");
// 2. Remove step from current chained list
if (afterStep != null) {
scoreDirector.beforeVariableChanged(afterStep, "previousStep");
afterStep.setPreviousStep(beforeStep);
scoreDirector.afterVariableChanged(afterStep, "previousStep");
}
}
The idea being that at no point I'm doing an invalid chained list manipulation:
However, as the title and the code comment indicate, I am getting a NullPointerException when I call scoreDirector.beforeVariableChanged. None of my variables are null (I've printed them to make sure). The NullPointerException doesn't occur in my code, but deep inside Optaplanner's inner workings, making it difficult for me to fix it:
Exception in thread "main" java.lang.NullPointerException
at org.drools.core.common.NamedEntryPoint.update(NamedEntryPoint.java:353)
at org.drools.core.common.NamedEntryPoint.update(NamedEntryPoint.java:338)
at org.drools.core.impl.StatefulKnowledgeSessionImpl.update(StatefulKnowledgeSessionImpl.java:1579)
at org.drools.core.impl.StatefulKnowledgeSessionImpl.update(StatefulKnowledgeSessionImpl.java:1551)
at org.optaplanner.core.impl.score.stream.drools.DroolsConstraintSession.update(DroolsConstraintSession.java:49)
at org.optaplanner.core.impl.score.director.stream.ConstraintStreamScoreDirector.afterVariableChanged(ConstraintStreamScoreDirector.java:137)
at org.optaplanner.core.impl.domain.variable.inverserelation.SingletonInverseVariableListener.retract(SingletonInverseVariableListener.java:96)
at org.optaplanner.core.impl.domain.variable.inverserelation.SingletonInverseVariableListener.beforeVariableChanged(SingletonInverseVariableListener.java:46)
at org.optaplanner.core.impl.domain.variable.listener.support.VariableListenerSupport.beforeVariableChanged(VariableListenerSupport.java:170)
at org.optaplanner.core.impl.score.director.AbstractScoreDirector.beforeVariableChanged(AbstractScoreDirector.java:430)
at org.optaplanner.core.impl.score.director.AbstractScoreDirector.beforeVariableChanged(AbstractScoreDirector.java:390)
at test.optaplanner.solver.AssignMove.assignStep(AssignMove.java:98)
at test.optaplanner.solver.AssignMove.doMoveOnGenuineVariables(AssignMove.java:85)
at org.optaplanner.core.impl.heuristic.move.AbstractMove.doMove(AbstractMove.java:35)
at org.optaplanner.core.impl.heuristic.move.AbstractMove.doMove(AbstractMove.java:30)
at org.optaplanner.core.impl.score.director.AbstractScoreDirector.doAndProcessMove(AbstractScoreDirector.java:187)
at org.optaplanner.core.impl.localsearch.decider.LocalSearchDecider.doMove(LocalSearchDecider.java:132)
at org.optaplanner.core.impl.localsearch.decider.LocalSearchDecider.decideNextStep(LocalSearchDecider.java:116)
at org.optaplanner.core.impl.localsearch.DefaultLocalSearchPhase.solve(DefaultLocalSearchPhase.java:70)
at org.optaplanner.core.impl.solver.AbstractSolver.runPhases(AbstractSolver.java:98)
at org.optaplanner.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:189)
at test.optaplanner.OptaPlannerService.testOptaplanner(OptaPlannerService.java:68)
at test.optaplanner.App.main(App.java:13)
Is there something I did wrong? It seems I am following the documentation for custom moves fairly closely, outside of the fact that I am using exclusively java code instead of drools.
The initial solution I feed to the solver has all of the steps assigned to a single driver. There are 15 drivers and 40 orders.
In order to bypass this error, I have tried a number of different things:
remove the shadow variable annotation, turn Driver into a problem fact, and handle the nextStep field myself => this makes no difference
use Simulated Annealing + First Fit Decreasing construction heuristics, and start with steps not assigned to any driver (this was inspired by looking up the example here, which is more complete than the one from the documentation) => the NullPointerException appears on afterVariableChanged instead, but it still appears.
a number of other things which were probably not very smart
But without a more helpful error message, I can't think of anything else to try.
Thank you for your help

Asynchronous callback - gwt

I am using gwt and postgres for my project. On the front end i have few widgets whose data i am trying to save on to tables at the back-end when i click on "save project" button(this also takes the name for the created project).
In the asynchronous callback part i am setting more than one table. But it is not sending the data properly. I am getting the following error:
org.postgresql.util.PSQLException: ERROR: insert or update on table "entitytype" violates foreign key constraint "entitytype_pname_fkey"
Detail: Key (pname)=(Project Name) is not present in table "project".
But when i do the select statement on project table i can see that the project name is present.
Here is how the callback part looks like:
oksave.addClickHandler(new ClickHandler(){
#Override
public void onClick(ClickEvent event) {
if(erasync == null)
erasync = GWT.create(EntityRelationService.class);
AsyncCallback<Void> callback = new AsyncCallback<Void>(){
#Override
public void onFailure(Throwable caught) {
}
#Override
public void onSuccess(Void result){ }
};
erasync.setProjects(projectname, callback);
for(int i = 0; i < boundaryPanel.getWidgetCount(); i++){
top = new Integer(boundaryPanel.getWidget(i).getAbsoluteTop()).toString();
left = new Integer(boundaryPanel.getWidget(i).getAbsoluteLeft()).toString();
if(widgetTitle.startsWith("ATTR")){
type = "regular";
erasync.setEntityAttribute(name1, name, type, top, left, projectname, callback);
} else{
erasync.setEntityType(name, top, left, projectname, callback);
}
}
}
Question:
Is it wrong to set more than one in the asynchronous callback where all the other tables are dependent on a particular table?
when i say setProjects in the above code isn't it first completed and then moved on to the next one?
Please any input will be greatly appreciated.
Thank you.
With that foreign key constraint, you must make sure the erasync.setProjects(...) has completed before you insert the rest of the stuff.
I suggest doing the erasync.setEntityAttribute(...) magic in (or from) an onsuccess callback instead of jumping right to it.
You're firing several request in which (guessing from the error message) really should be called in sequence.
Any time you call more than one rpc call; try to think that you should be able to rearrange them in any order (because that's allmost what actually happens because they're asynchronous)... If running them in reverse order does not make sense; you cannot fire them sequentially!
Two ways to fix your problem:
Nesting:
service.callFirst(someData, new AsyncCallback<Void> callback = new AsyncCallback<Void>(){
#Override
public void onFailure(Throwable caught) {/*Handle errors*/}
#Override
public void onSuccess(Void result){
service.callSecond(someOtherData, new AsyncCallback<Void> callback = new AsyncCallback<Void>(){
/* onSuccess and onFailure for second callback here */
});
}
});
Or creating one service call that does both (Recommended):
service.callFirstAndSecond(someData, someOtherData, new AsyncCallback<Void> callback = new AsyncCallback<Void>(){
#Override
public void onFailure(Throwable caught) {/*Handle errors*/}
#Override
public void onSuccess(Void result){
/* Handle success */
}
});
The second option is most likely going to be much less messy, as several nested asynch callbacks quickly grows quite wide and confusing, also you make just one request.
Because of nature of Async, don't assume setProjects(...) method will be called on the server before setEntityAttribute or setEntityType.
Personally, I prefer to have a Project class which contains all necessary info, for example:
public class Project{
private String projectName;
private List attributes = new ArrayList();
.. other properties
// Getter & Setter methods
}
Then send to the server in one round trip:
Project project = new Project();
project.setProjectName(..);
// Set other properties
erasync.saveProjects(project, callback);