diff --git a/java/food-ordering/README.md b/java/food-ordering/README.md index bff99915..4709a7bb 100644 --- a/java/food-ordering/README.md +++ b/java/food-ordering/README.md @@ -11,6 +11,13 @@ It also interacts with the delivery services to get the order delivered to the c ## Running locally with Docker compose +Build the docker containers: + +```shell +cd app +./gradlew clean build jibDockerBuild +``` + Launch the Docker compose setup: ```shell docker compose up @@ -90,4 +97,4 @@ Then run the example via Docker compose. ### Upgrading Restate runtime The Docker Compose setup uses the latest Restate runtime version. -Test run the example via Docker compose. \ No newline at end of file +Test run the example via Docker compose. diff --git a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/DeliveryManager.java b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/DeliveryManager.java index 8e549fb4..eeed3df8 100644 --- a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/DeliveryManager.java +++ b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/DeliveryManager.java @@ -1,15 +1,20 @@ package dev.restate.sdk.examples; +import static dev.restate.sdk.examples.generated.OrderProto.*; import static dev.restate.sdk.examples.utils.TypeUtils.statusToProto; import dev.restate.sdk.RestateContext; import dev.restate.sdk.common.CoreSerdes; +import dev.restate.sdk.common.Serde; import dev.restate.sdk.common.StateKey; import dev.restate.sdk.common.TerminalException; -import dev.restate.sdk.examples.generated.*; +import dev.restate.sdk.examples.generated.DeliveryManagerRestate; +import dev.restate.sdk.examples.generated.DriverDeliveryMatcherRestate; +import dev.restate.sdk.examples.generated.DriverDigitalTwinRestate; +import dev.restate.sdk.examples.generated.OrderStatusServiceRestate; import dev.restate.sdk.examples.types.DeliveryInformation; import dev.restate.sdk.examples.types.Location; -import dev.restate.sdk.examples.types.Status; +import dev.restate.sdk.examples.types.StatusEnum; import dev.restate.sdk.examples.utils.GeoUtils; import dev.restate.sdk.serde.jackson.JacksonSerdes; @@ -23,19 +28,18 @@ public class DeliveryManager extends DeliveryManagerRestate.DeliveryManagerResta StateKey DELIVERY_INFO = StateKey.of("delivery-info", JacksonSerdes.of(DeliveryInformation.class)); + private static final Serde locationSerde = JacksonSerdes.of(Location.class); + /** * Finds a driver, assigns the delivery job to the driver, and updates the status of the order. * Gets called by the OrderService when a new order has been prepared and needs to be delivered. */ @Override - public void start(RestateContext ctx, OrderProto.DeliveryRequest request) - throws TerminalException { + public void start(RestateContext ctx, DeliveryRequest request) throws TerminalException { // Temporary placeholder: random location - var restaurantLocation = - ctx.sideEffect(JacksonSerdes.of(Location.class), () -> GeoUtils.randomLocation()); - var customerLocation = - ctx.sideEffect(JacksonSerdes.of(Location.class), () -> GeoUtils.randomLocation()); + var restaurantLocation = ctx.sideEffect(locationSerde, () -> GeoUtils.randomLocation()); + var customerLocation = ctx.sideEffect(locationSerde, () -> GeoUtils.randomLocation()); // Store the delivery information in Restate's state store DeliveryInformation deliveryInfo = @@ -53,7 +57,7 @@ public void start(RestateContext ctx, OrderProto.DeliveryRequest request) DriverDeliveryMatcherRestate.newClient(ctx) .oneWay() .requestDriverForDelivery( - OrderProto.DeliveryCallback.newBuilder() + DeliveryCallback.newBuilder() .setRegion(GeoUtils.DEMO_REGION) .setDeliveryCallbackId(driverAwakeable.id()) .build()); @@ -65,7 +69,7 @@ public void start(RestateContext ctx, OrderProto.DeliveryRequest request) // Assign the driver to the job DriverDigitalTwinRestate.newClient(ctx) .assignDeliveryJob( - OrderProto.AssignDeliveryRequest.newBuilder() + AssignDeliveryRequest.newBuilder() .setDriverId(driverId) .setOrderId(request.getOrderId()) .setRestaurantId(request.getRestaurantId()) @@ -77,7 +81,7 @@ public void start(RestateContext ctx, OrderProto.DeliveryRequest request) // Update the status of the order to "waiting for the driver" OrderStatusServiceRestate.newClient(ctx) .oneWay() - .setStatus(statusToProto(request.getOrderId(), Status.WAITING_FOR_DRIVER)); + .setStatus(statusToProto(request.getOrderId(), StatusEnum.WAITING_FOR_DRIVER)); } /** @@ -85,8 +89,7 @@ public void start(RestateContext ctx, OrderProto.DeliveryRequest request) * when the driver has arrived at the restaurant. */ @Override - public void notifyDeliveryPickup(RestateContext ctx, OrderProto.OrderId request) - throws TerminalException { + public void notifyDeliveryPickup(RestateContext ctx, OrderId request) throws TerminalException { // Retrieve the delivery information for this delivery var delivery = ctx.get(DELIVERY_INFO) @@ -95,13 +98,13 @@ public void notifyDeliveryPickup(RestateContext ctx, OrderProto.OrderId request) new TerminalException( "Delivery was picked up but there is no ongoing delivery.")); // Update the status of the delivery to "picked up" - delivery.setOrderPickedUp(true); + delivery.notifyPickup(); ctx.set(DELIVERY_INFO, delivery); // Update the status of the order to "in delivery" OrderStatusServiceRestate.newClient(ctx) .oneWay() - .setStatus(statusToProto(delivery.getOrderId(), Status.IN_DELIVERY)); + .setStatus(statusToProto(delivery.getOrderId(), StatusEnum.IN_DELIVERY)); } /** @@ -109,7 +112,7 @@ public void notifyDeliveryPickup(RestateContext ctx, OrderProto.OrderId request) * when the driver has delivered the order to the customer. */ @Override - public void notifyDeliveryDelivered(RestateContext ctx, OrderProto.OrderId request) + public void notifyDeliveryDelivered(RestateContext ctx, OrderId request) throws TerminalException { // Retrieve the delivery information for this delivery var delivery = @@ -131,8 +134,8 @@ public void notifyDeliveryDelivered(RestateContext ctx, OrderProto.OrderId reque * has moved to a new location. */ @Override - public void handleDriverLocationUpdate( - RestateContext ctx, OrderProto.DeliveryLocationUpdate request) throws TerminalException { + public void handleDriverLocationUpdate(RestateContext ctx, DeliveryLocationUpdate request) + throws TerminalException { // Retrieve the delivery information for this delivery var delivery = ctx.get(DELIVERY_INFO) @@ -153,10 +156,6 @@ public void handleDriverLocationUpdate( // Update the ETA of the order OrderStatusServiceRestate.newClient(ctx) .oneWay() - .setETA( - OrderProto.OrderStatus.newBuilder() - .setOrderId(delivery.getOrderId()) - .setEta(eta) - .build()); + .setETA(OrderStatus.newBuilder().setOrderId(delivery.getOrderId()).setEta(eta).build()); } } diff --git a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/DriverDeliveryMatcher.java b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/DriverDeliveryMatcher.java index 6a9caff9..fd8ebab9 100644 --- a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/DriverDeliveryMatcher.java +++ b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/DriverDeliveryMatcher.java @@ -1,12 +1,13 @@ package dev.restate.sdk.examples; +import static dev.restate.sdk.examples.generated.OrderProto.*; + import com.fasterxml.jackson.core.type.TypeReference; import dev.restate.sdk.RestateContext; import dev.restate.sdk.common.CoreSerdes; import dev.restate.sdk.common.StateKey; import dev.restate.sdk.common.TerminalException; import dev.restate.sdk.examples.generated.DriverDeliveryMatcherRestate; -import dev.restate.sdk.examples.generated.OrderProto; import dev.restate.sdk.serde.jackson.JacksonSerdes; import java.util.LinkedList; import java.util.Queue; @@ -32,8 +33,7 @@ public class DriverDeliveryMatcher * in line. If no pending deliveries, driver is added to the available driver pool */ @Override - public void setDriverAvailable( - RestateContext ctx, OrderProto.DriverPoolAvailableNotification request) + public void setDriverAvailable(RestateContext ctx, DriverPoolAvailableNotification request) throws TerminalException { var pendingDeliveries = ctx.get(PENDING_DELIVERIES).orElse(new LinkedList<>()); @@ -58,7 +58,7 @@ public void setDriverAvailable( * available. If no available drivers, the delivery is added to the pending deliveries queue */ @Override - public void requestDriverForDelivery(RestateContext ctx, OrderProto.DeliveryCallback request) + public void requestDriverForDelivery(RestateContext ctx, DeliveryCallback request) throws TerminalException { var availableDrivers = ctx.get(AVAILABLE_DRIVERS).orElse(new LinkedList<>()); diff --git a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/DriverDigitalTwin.java b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/DriverDigitalTwin.java index 318686fc..7efb27c4 100644 --- a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/DriverDigitalTwin.java +++ b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/DriverDigitalTwin.java @@ -1,5 +1,6 @@ package dev.restate.sdk.examples; +import static dev.restate.sdk.examples.generated.OrderProto.*; import static dev.restate.sdk.examples.utils.TypeUtils.toOrderIdProto; import com.google.protobuf.Empty; @@ -9,8 +10,6 @@ import dev.restate.sdk.examples.generated.DeliveryManagerRestate; import dev.restate.sdk.examples.generated.DriverDeliveryMatcherRestate; import dev.restate.sdk.examples.generated.DriverDigitalTwinRestate; -import dev.restate.sdk.examples.generated.OrderProto; -import dev.restate.sdk.examples.generated.OrderProto.AssignDeliveryRequest; import dev.restate.sdk.examples.types.AssignedDelivery; import dev.restate.sdk.examples.types.DriverStatus; import dev.restate.sdk.examples.types.Location; @@ -18,8 +17,8 @@ /** * Digital twin for the driver. Represents a driver and his status, assigned delivery, and location. - * Keyed by driver ID. The actual driver would have an application (mocked by DriverMobileAppSimulator - * ) that calls this service. + * Keyed by driver ID. The actual driver would have an application (mocked by + * DriverMobileAppSimulator ) that calls this service. */ public class DriverDigitalTwin extends DriverDigitalTwinRestate.DriverDigitalTwinRestateImplBase { @@ -36,11 +35,11 @@ public class DriverDigitalTwin extends DriverDigitalTwinRestate.DriverDigitalTwi StateKey.of("driver-location", JacksonSerdes.of(Location.class)); /** - * When the driver starts his work day or finishes a delivery, his application (DriverMobileAppSimulator) - * calls this method. + * When the driver starts his work day or finishes a delivery, his application + * (DriverMobileAppSimulator) calls this method. */ @Override - public void setDriverAvailable(RestateContext ctx, OrderProto.DriverAvailableNotification request) + public void setDriverAvailable(RestateContext ctx, DriverAvailableNotification request) throws TerminalException { expectStatus(ctx, DriverStatus.IDLE); @@ -48,7 +47,7 @@ public void setDriverAvailable(RestateContext ctx, OrderProto.DriverAvailableNot DriverDeliveryMatcherRestate.newClient(ctx) .oneWay() .setDriverAvailable( - OrderProto.DriverPoolAvailableNotification.newBuilder() + DriverPoolAvailableNotification.newBuilder() .setRegion(request.getRegion()) .setDriverId(request.getDriverId()) .build()); @@ -82,7 +81,7 @@ public void assignDeliveryJob(RestateContext ctx, AssignDeliveryRequest request) DeliveryManagerRestate.newClient(ctx) .oneWay() .handleDriverLocationUpdate( - OrderProto.DeliveryLocationUpdate.newBuilder() + DeliveryLocationUpdate.newBuilder() .setOrderId(request.getOrderId()) .setLocation(loc.toProto()) .build())); @@ -92,8 +91,7 @@ public void assignDeliveryJob(RestateContext ctx, AssignDeliveryRequest request) * Gets called by the driver's mobile app when he has picked up the delivery from the restaurant. */ @Override - public void notifyDeliveryPickup(RestateContext ctx, OrderProto.DriverId request) - throws TerminalException { + public void notifyDeliveryPickup(RestateContext ctx, DriverId request) throws TerminalException { expectStatus(ctx, DriverStatus.DELIVERING); // Retrieve the ongoing delivery and update its status @@ -109,14 +107,12 @@ public void notifyDeliveryPickup(RestateContext ctx, OrderProto.DriverId request // Update the status of the delivery in the delivery manager DeliveryManagerRestate.newClient(ctx) .oneWay() - .notifyDeliveryPickup(toOrderIdProto(currentDelivery.orderId)); + .notifyDeliveryPickup(toOrderIdProto(currentDelivery.getOrderId())); } - /** - * Gets called by the driver's mobile app when he has delivered the order to the customer. - */ + /** Gets called by the driver's mobile app when he has delivered the order to the customer. */ @Override - public void notifyDeliveryDelivered(RestateContext ctx, OrderProto.DriverId request) + public void notifyDeliveryDelivered(RestateContext ctx, DriverId request) throws TerminalException { expectStatus(ctx, DriverStatus.DELIVERING); @@ -133,7 +129,7 @@ public void notifyDeliveryDelivered(RestateContext ctx, OrderProto.DriverId requ // Notify the delivery service that the delivery was delivered DeliveryManagerRestate.newClient(ctx) .oneWay() - .notifyDeliveryDelivered(toOrderIdProto(assignedDelivery.orderId)); + .notifyDeliveryDelivered(toOrderIdProto(assignedDelivery.getOrderId())); // Update the status of the driver to idle ctx.set(DRIVER_STATUS, DriverStatus.IDLE); @@ -141,8 +137,8 @@ public void notifyDeliveryDelivered(RestateContext ctx, OrderProto.DriverId requ /** Gets called by the driver's mobile app when he has moved to a new location. */ @Override - public void handleDriverLocationUpdateEvent( - RestateContext ctx, OrderProto.KafkaDriverLocationEvent request) throws TerminalException { + public void handleDriverLocationUpdateEvent(RestateContext ctx, KafkaDriverLocationEvent request) + throws TerminalException { // Update the location of the driver Location location = JacksonSerdes.of(Location.class).deserialize(request.getLocation()); ctx.set(DRIVER_LOCATION, location); @@ -154,8 +150,8 @@ public void handleDriverLocationUpdateEvent( DeliveryManagerRestate.newClient(ctx) .oneWay() .handleDriverLocationUpdate( - OrderProto.DeliveryLocationUpdate.newBuilder() - .setOrderId(delivery.orderId) + DeliveryLocationUpdate.newBuilder() + .setOrderId(delivery.getOrderId()) .setLocation(location.toProto()) .build())); } @@ -166,27 +162,24 @@ public void handleDriverLocationUpdateEvent( * got assigned to him. */ @Override - public OrderProto.AssignedDeliveryResponse getAssignedDelivery( - RestateContext ctx, OrderProto.DriverId request) throws TerminalException { + public AssignedDeliveryResponse getAssignedDelivery(RestateContext ctx, DriverId request) + throws TerminalException { var assignedDelivery = ctx.get(ASSIGNED_DELIVERY); return assignedDelivery .map( delivery -> - OrderProto.AssignedDeliveryResponse.newBuilder() + AssignedDeliveryResponse.newBuilder() .setDelivery( - OrderProto.Delivery.newBuilder() - .setDriverId(delivery.driverId) - .setOrderId(delivery.orderId) - .setRestaurantId(delivery.restaurantId) - .setCustomerLocation(delivery.customerLocation.toProto()) - .setRestaurantLocation(delivery.restaurantLocation.toProto()) + Delivery.newBuilder() + .setDriverId(delivery.getDriverId()) + .setOrderId(delivery.getOrderId()) + .setRestaurantId(delivery.getRestaurantId()) + .setCustomerLocation(delivery.getCustomerLocation().toProto()) + .setRestaurantLocation(delivery.getRestaurantLocation().toProto()) .build()) .build()) - .orElse( - OrderProto.AssignedDeliveryResponse.newBuilder() - .setEmpty(Empty.getDefaultInstance()) - .build()); + .orElse(AssignedDeliveryResponse.newBuilder().setEmpty(Empty.getDefaultInstance()).build()); } // Utility function to check if the driver is in the expected state diff --git a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/OrderStatusService.java b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/OrderStatusService.java index 1bf965be..7e738d4d 100644 --- a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/OrderStatusService.java +++ b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/OrderStatusService.java @@ -1,12 +1,13 @@ package dev.restate.sdk.examples; +import static dev.restate.sdk.examples.generated.OrderProto.*; + import dev.restate.sdk.RestateContext; import dev.restate.sdk.common.CoreSerdes; import dev.restate.sdk.common.StateKey; import dev.restate.sdk.common.TerminalException; -import dev.restate.sdk.examples.generated.OrderProto; import dev.restate.sdk.examples.generated.OrderStatusServiceRestate; -import dev.restate.sdk.examples.types.Status; +import dev.restate.sdk.examples.types.StatusEnum; public class OrderStatusService extends OrderStatusServiceRestate.OrderStatusServiceRestateImplBase { @@ -15,26 +16,24 @@ public class OrderStatusService /** Gets called by the webUI frontend to display the status of an order. */ @Override - public OrderProto.OrderStatus get(RestateContext ctx, OrderProto.OrderId request) - throws TerminalException { + public OrderStatus get(RestateContext ctx, OrderId request) throws TerminalException { var orderStatusState = ctx.get(ORDER_STATUS).orElse("NEW"); - var status = Status.valueOf(orderStatusState); + var status = StatusEnum.valueOf(orderStatusState); var eta = ctx.get(ORDER_ETA).orElse(-1L); - return OrderProto.OrderStatus.newBuilder() + return OrderStatus.newBuilder() .setOrderId(request.getOrderId()) - .setStatus(OrderProto.Status.forNumber(status.getValue())) + .setStatus(Status.forNumber(status.getValue())) .setEta(eta) .build(); } @Override - public void setStatus(RestateContext ctx, OrderProto.OrderStatus request) - throws TerminalException { + public void setStatus(RestateContext ctx, OrderStatus request) throws TerminalException { ctx.set(ORDER_STATUS, request.getStatus().name()); } @Override - public void setETA(RestateContext ctx, OrderProto.OrderStatus request) throws TerminalException { + public void setETA(RestateContext ctx, OrderStatus request) throws TerminalException { ctx.set(ORDER_ETA, request.getEta()); } } diff --git a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/OrderWorkflow.java b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/OrderWorkflow.java index 1068d31d..00c2c695 100644 --- a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/OrderWorkflow.java +++ b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/OrderWorkflow.java @@ -10,11 +10,11 @@ import dev.restate.sdk.examples.clients.PaymentClient; import dev.restate.sdk.examples.clients.RestaurantClient; import dev.restate.sdk.examples.generated.DeliveryManagerRestate; -import dev.restate.sdk.examples.generated.OrderProto; +import dev.restate.sdk.examples.generated.OrderProto.*; import dev.restate.sdk.examples.generated.OrderStatusServiceRestate; import dev.restate.sdk.examples.generated.OrderWorkflowRestate; import dev.restate.sdk.examples.types.OrderRequest; -import dev.restate.sdk.examples.types.Status; +import dev.restate.sdk.examples.types.StatusEnum; import java.time.Duration; import java.util.UUID; @@ -28,52 +28,53 @@ public class OrderWorkflow extends OrderWorkflowRestate.OrderWorkflowRestateImpl private final PaymentClient paymentClnt = PaymentClient.get(); @Override - public void handleOrderCreationEvent(RestateContext ctx, OrderProto.KafkaOrderEvent event) + public void handleOrderCreationEvent(RestateContext ctx, KafkaOrderEvent event) throws TerminalException { var orderStatusSend = OrderStatusServiceRestate.newClient(ctx); try { ObjectMapper mapper = new ObjectMapper(); OrderRequest order = mapper.readValue(event.getPayload().toStringUtf8(), OrderRequest.class); + String id = order.getOrderId(); // 1. Set status - orderStatusSend.oneWay().setStatus(statusToProto(order.orderId, Status.CREATED)); + orderStatusSend.oneWay().setStatus(statusToProto(id, StatusEnum.CREATED)); // 2. Handle payment String token = ctx.sideEffect(CoreSerdes.STRING_UTF8, () -> UUID.randomUUID().toString()); boolean paid = ctx.sideEffect( - CoreSerdes.BOOLEAN, () -> paymentClnt.charge(order.orderId, token, order.totalCost)); + CoreSerdes.BOOLEAN, () -> paymentClnt.charge(id, token, order.getTotalCost())); if (!paid) { - orderStatusSend.oneWay().setStatus(statusToProto(order.orderId, Status.REJECTED)); + orderStatusSend.oneWay().setStatus(statusToProto(id, StatusEnum.REJECTED)); return; } // 3. Schedule preparation - orderStatusSend.setStatus(statusToProto(order.orderId, Status.SCHEDULED)); - ctx.sleep(Duration.ofMillis(order.deliveryDelay)); + orderStatusSend.setStatus(statusToProto(order.getOrderId(), StatusEnum.SCHEDULED)); + ctx.sleep(Duration.ofMillis(order.getDeliveryDelay())); // 4. Trigger preparation var preparationAwakeable = ctx.awakeable(CoreSerdes.VOID); - ctx.sideEffect(() -> restaurant.prepare(order.orderId, preparationAwakeable.id())); - orderStatusSend.setStatus(statusToProto(order.orderId, Status.IN_PREPARATION)); + ctx.sideEffect(() -> restaurant.prepare(id, preparationAwakeable.id())); + orderStatusSend.setStatus(statusToProto(id, StatusEnum.IN_PREPARATION)); preparationAwakeable.await(); - orderStatusSend.setStatus(statusToProto(order.orderId, Status.SCHEDULING_DELIVERY)); + orderStatusSend.setStatus(statusToProto(id, StatusEnum.SCHEDULING_DELIVERY)); // 5. Find a driver and start delivery var deliveryAwakeable = ctx.awakeable(CoreSerdes.VOID); var deliveryRequest = - OrderProto.DeliveryRequest.newBuilder() - .setOrderId(order.orderId) - .setRestaurantId(order.restaurantId) + DeliveryRequest.newBuilder() + .setOrderId(id) + .setRestaurantId(order.getRestaurantId()) .setCallback(deliveryAwakeable.id()) .build(); DeliveryManagerRestate.newClient(ctx).oneWay().start(deliveryRequest); deliveryAwakeable.await(); - orderStatusSend.setStatus(statusToProto(order.orderId, Status.DELIVERED)); + orderStatusSend.setStatus(statusToProto(order.getOrderId(), StatusEnum.DELIVERED)); } catch (JsonProcessingException e) { throw new TerminalException("Parsing raw JSON order failed: " + e.getMessage()); diff --git a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/external/DriverMobileAppSimulator.java b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/external/DriverMobileAppSimulator.java index 4b5d312b..68f4bc29 100644 --- a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/external/DriverMobileAppSimulator.java +++ b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/external/DriverMobileAppSimulator.java @@ -1,12 +1,13 @@ package dev.restate.sdk.examples.external; +import static dev.restate.sdk.examples.generated.OrderProto.*; + import dev.restate.sdk.RestateContext; import dev.restate.sdk.common.StateKey; import dev.restate.sdk.common.TerminalException; import dev.restate.sdk.examples.clients.KafkaPublisher; import dev.restate.sdk.examples.generated.DriverDigitalTwinRestate; import dev.restate.sdk.examples.generated.DriverMobileAppSimulatorRestate; -import dev.restate.sdk.examples.generated.OrderProto; import dev.restate.sdk.examples.types.AssignedDelivery; import dev.restate.sdk.examples.types.Location; import dev.restate.sdk.examples.utils.GeoUtils; @@ -21,7 +22,7 @@ * This would actually be a mobile app that drivers use to accept delivery requests, and to set * themselves as available. * - * For simplicity, we implemented this with Restate. + *

For simplicity, we implemented this with Restate. */ public class DriverMobileAppSimulator extends DriverMobileAppSimulatorRestate.DriverMobileAppSimulatorRestateImplBase { @@ -39,12 +40,9 @@ public class DriverMobileAppSimulator StateKey ASSIGNED_DELIVERY = StateKey.of("assigned-delivery", JacksonSerdes.of(AssignedDelivery.class)); - /** - * Mimics the driver setting himself to available in the app - */ + /** Mimics the driver setting himself to available in the app */ @Override - public void startDriver(RestateContext ctx, OrderProto.DriverId request) - throws TerminalException { + public void startDriver(RestateContext ctx, DriverId request) throws TerminalException { // If this driver was already created, do nothing if (ctx.get(CURRENT_LOCATION).isPresent()) { return; @@ -59,7 +57,7 @@ public void startDriver(RestateContext ctx, OrderProto.DriverId request) // Tell the digital twin of the driver in the food ordering app, that he is available DriverDigitalTwinRestate.newClient(ctx) .setDriverAvailable( - OrderProto.DriverAvailableNotification.newBuilder() + DriverAvailableNotification.newBuilder() .setDriverId(request.getDriverId()) .setRegion(GeoUtils.DEMO_REGION) .build()) @@ -74,8 +72,7 @@ public void startDriver(RestateContext ctx, OrderProto.DriverId request) * again after a short delay. */ @Override - public void pollForWork(RestateContext ctx, OrderProto.DriverId request) - throws TerminalException { + public void pollForWork(RestateContext ctx, DriverId request) throws TerminalException { var thisDriverSim = DriverMobileAppSimulatorRestate.newClient(ctx); // Ask the digital twin of the driver in the food ordering app, if he already got a job assigned @@ -103,11 +100,9 @@ public void pollForWork(RestateContext ctx, OrderProto.DriverId request) thisDriverSim.delayed(Duration.ofMillis(MOVE_INTERVAL)).move(request); } - /** - * Periodically lets the food ordering app know the new location - */ + /** Periodically lets the food ordering app know the new location */ @Override - public void move(RestateContext ctx, OrderProto.DriverId request) throws TerminalException { + public void move(RestateContext ctx, DriverId request) throws TerminalException { var thisDriverSim = DriverMobileAppSimulatorRestate.newClient(ctx); var assignedDelivery = ctx.get(ASSIGNED_DELIVERY) @@ -118,9 +113,9 @@ public void move(RestateContext ctx, OrderProto.DriverId request) throws Termina // Get next destination to go to var nextDestination = - assignedDelivery.orderPickedUp - ? assignedDelivery.customerLocation - : assignedDelivery.restaurantLocation; + assignedDelivery.isOrderPickedUp() + ? assignedDelivery.getCustomerLocation() + : assignedDelivery.getRestaurantLocation(); // Move to the next location var newLocation = GeoUtils.moveToDestination(currentLocation, nextDestination); @@ -131,7 +126,7 @@ public void move(RestateContext ctx, OrderProto.DriverId request) throws Termina // If we reached the destination, notify the food ordering app if (newLocation.equals(nextDestination)) { // If the delivery was already picked up, then that means it now arrived at the customer - if (assignedDelivery.orderPickedUp) { + if (assignedDelivery.isOrderPickedUp()) { // Delivery is delivered to customer ctx.clear(ASSIGNED_DELIVERY); @@ -145,7 +140,7 @@ public void move(RestateContext ctx, OrderProto.DriverId request) throws Termina DriverDigitalTwinRestate.newClient(ctx) .oneWay() .setDriverAvailable( - OrderProto.DriverAvailableNotification.newBuilder() + DriverAvailableNotification.newBuilder() .setDriverId(request.getDriverId()) .setRegion(GeoUtils.DEMO_REGION) .build()); diff --git a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/types/AssignedDelivery.java b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/types/AssignedDelivery.java index d7298b06..55b43b1e 100644 --- a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/types/AssignedDelivery.java +++ b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/types/AssignedDelivery.java @@ -1,20 +1,24 @@ package dev.restate.sdk.examples.types; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + public class AssignedDelivery { - public String driverId; - public String orderId; - public String restaurantId; - public Location restaurantLocation; - public Location customerLocation; - public boolean orderPickedUp = false; + private final String driverId; + private final String orderId; + private final String restaurantId; + private final Location restaurantLocation; + private final Location customerLocation; + private boolean orderPickedUp = false; + @JsonCreator public AssignedDelivery( - String driverId, - String orderId, - String restaurantId, - Location restaurantLocation, - Location customerLocation) { + @JsonProperty("driverId") String driverId, + @JsonProperty("orderId") String orderId, + @JsonProperty("restaurantId") String restaurantId, + @JsonProperty("restaurantLocation") Location restaurantLocation, + @JsonProperty("customerLocation") Location customerLocation) { this.driverId = driverId; this.orderId = orderId; this.restaurantId = restaurantId; @@ -22,9 +26,31 @@ public AssignedDelivery( this.customerLocation = customerLocation; } - public AssignedDelivery() {} + public String getDriverId() { + return driverId; + } + + public String getOrderId() { + return orderId; + } + + public String getRestaurantId() { + return restaurantId; + } + + public Location getRestaurantLocation() { + return restaurantLocation; + } + + public Location getCustomerLocation() { + return customerLocation; + } + + public boolean isOrderPickedUp() { + return orderPickedUp; + } public void notifyPickup() { - this.orderPickedUp = true; + orderPickedUp = true; } } diff --git a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/types/DeliveryInformation.java b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/types/DeliveryInformation.java index d51d1b21..69774ca3 100644 --- a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/types/DeliveryInformation.java +++ b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/types/DeliveryInformation.java @@ -1,20 +1,24 @@ package dev.restate.sdk.examples.types; -public class DeliveryInformation { - String orderId; - String callbackId; - String restaurantId; - Location restaurantLocation; - Location customerLocation; - boolean orderPickedUp; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +public class DeliveryInformation { + private final String orderId; + private final String callbackId; + private final String restaurantId; + private final Location restaurantLocation; + private final Location customerLocation; + private boolean orderPickedUp; + + @JsonCreator public DeliveryInformation( - String orderId, - String callbackId, - String restaurantId, - Location restaurantLocation, - Location customerLocation, - boolean orderPickedUp) { + @JsonProperty("orderId") String orderId, + @JsonProperty("callbackId") String callbackId, + @JsonProperty("restaurantId") String restaurantId, + @JsonProperty("restaurantLocation") Location restaurantLocation, + @JsonProperty("customerLocation") Location customerLocation, + @JsonProperty("orderPickedUp") boolean orderPickedUp) { this.orderId = orderId; this.callbackId = callbackId; this.restaurantId = restaurantId; @@ -23,53 +27,31 @@ public DeliveryInformation( this.orderPickedUp = orderPickedUp; } - public DeliveryInformation() {} - public String getOrderId() { return orderId; } - public void setOrderId(String orderId) { - this.orderId = orderId; - } - public String getCallbackId() { return callbackId; } - public void setCallbackId(String callbackId) { - this.callbackId = callbackId; - } - public String getRestaurantId() { return restaurantId; } - public void setRestaurantId(String restaurantId) { - this.restaurantId = restaurantId; - } - public Location getRestaurantLocation() { return restaurantLocation; } - public void setRestaurantLocation(Location restaurantLocation) { - this.restaurantLocation = restaurantLocation; - } - public Location getCustomerLocation() { return customerLocation; } - public void setCustomerLocation(Location customerLocation) { - this.customerLocation = customerLocation; - } - public boolean isOrderPickedUp() { return orderPickedUp; } - public void setOrderPickedUp(boolean orderPickedUp) { - this.orderPickedUp = orderPickedUp; + public void notifyPickup() { + this.orderPickedUp = true; } } diff --git a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/types/Location.java b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/types/Location.java index 8b1fd47a..7e912859 100644 --- a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/types/Location.java +++ b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/types/Location.java @@ -1,34 +1,27 @@ package dev.restate.sdk.examples.types; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; import dev.restate.sdk.examples.generated.OrderProto; public class Location { - public double lon; - public double lat; + private final double lon; + private final double lat; - public Location(double lon, double lat) { + @JsonCreator + public Location(@JsonProperty("lon") double lon, @JsonProperty("lat") double lat) { this.lon = lon; this.lat = lat; } - public Location() {} - public double getLon() { return lon; } - public void setLon(double lon) { - this.lon = lon; - } - public double getLat() { return lat; } - public void setLat(double lat) { - this.lat = lat; - } - public static Location fromProto(OrderProto.Location proto) { return new Location(proto.getLon(), proto.getLat()); } diff --git a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/types/OrderRequest.java b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/types/OrderRequest.java index 0dba686f..c3b01916 100644 --- a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/types/OrderRequest.java +++ b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/types/OrderRequest.java @@ -1,28 +1,23 @@ package dev.restate.sdk.examples.types; +import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; public class OrderRequest { - @JsonProperty("order_id") - public String orderId; - @JsonProperty("restaurant_id") - public String restaurantId; - - public Product[] products; - - @JsonProperty("total_cost") - public double totalCost; - - @JsonProperty("delivery_delay") - public int deliveryDelay; + private final String orderId; + private final String restaurantId; + private final Product[] products; + private final double totalCost; + private final int deliveryDelay; + @JsonCreator public OrderRequest( - String orderId, - String restaurantId, - Product[] products, - double totalCost, - int deliveryDelay) { + @JsonProperty("orderId") String orderId, + @JsonProperty("restaurantId") String restaurantId, + @JsonProperty("products") Product[] products, + @JsonProperty("totalCost") double totalCost, + @JsonProperty("deliveryDelay") int deliveryDelay) { this.orderId = orderId; this.restaurantId = restaurantId; this.products = products; @@ -30,5 +25,19 @@ public OrderRequest( this.deliveryDelay = deliveryDelay; } - public OrderRequest() {} + public String getOrderId() { + return orderId; + } + + public String getRestaurantId() { + return restaurantId; + } + + public double getTotalCost() { + return totalCost; + } + + public int getDeliveryDelay() { + return deliveryDelay; + } } diff --git a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/types/Product.java b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/types/Product.java index c20bcbb1..dcbd61af 100644 --- a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/types/Product.java +++ b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/types/Product.java @@ -3,41 +3,17 @@ import com.fasterxml.jackson.annotation.JsonProperty; public class Product { - @JsonProperty("product_id") - public String productId; - public String description; - public int quantity; + private final String productId; + private final String description; + private final int quantity; - public Product(String productId, String description, int quantity) { + public Product( + @JsonProperty("productId") String productId, + @JsonProperty("description") String description, + @JsonProperty("quantity") int quantity) { this.productId = productId; this.description = description; this.quantity = quantity; } - - public Product() {} - - public String getProductId() { - return productId; - } - - public void setProductId(String productId) { - this.productId = productId; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public int getQuantity() { - return quantity; - } - - public void setQuantity(int quantity) { - this.quantity = quantity; - } } diff --git a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/types/Status.java b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/types/StatusEnum.java similarity index 86% rename from java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/types/Status.java rename to java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/types/StatusEnum.java index 723e4e69..05ec76cb 100644 --- a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/types/Status.java +++ b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/types/StatusEnum.java @@ -1,6 +1,6 @@ package dev.restate.sdk.examples.types; -public enum Status { +public enum StatusEnum { NEW(0), CREATED(1), SCHEDULED(2), @@ -15,7 +15,7 @@ public enum Status { private final int value; - Status(int value) { + StatusEnum(int value) { this.value = value; } diff --git a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/utils/GeoUtils.java b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/utils/GeoUtils.java index 879a0973..41a63801 100644 --- a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/utils/GeoUtils.java +++ b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/utils/GeoUtils.java @@ -21,19 +21,19 @@ public static Location randomLocation() { } public static Location moveToDestination(Location location, Location destination) { - double dx = destination.lon - location.lon; - double dy = destination.lat - location.lat; + double dx = destination.getLon() - location.getLon(); + double dy = destination.getLat() - location.getLat(); double distance = Math.sqrt(dx * dx + dy * dy); if (distance < SPEED) { return destination; } double ratio = SPEED / distance; - return new Location(location.lon + dx * ratio, location.lat + dy * ratio); + return new Location(location.getLon() + dx * ratio, location.getLat() + dy * ratio); } public static Long calculateEtaMillis(Location currentLocation, Location targetLocation) { - var longDiff = Math.abs(targetLocation.lon - currentLocation.lon); - var latDiff = Math.abs(targetLocation.lat - currentLocation.lat); + var longDiff = Math.abs(targetLocation.getLon() - currentLocation.getLon()); + var latDiff = Math.abs(targetLocation.getLat() - currentLocation.getLat()); var distance = Math.max(longDiff, latDiff); return Math.round(1000 * distance / SPEED); } diff --git a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/utils/TypeUtils.java b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/utils/TypeUtils.java index 63c2b04a..86a4bae0 100644 --- a/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/utils/TypeUtils.java +++ b/java/food-ordering/app/restate-app/src/main/java/dev/restate/sdk/examples/utils/TypeUtils.java @@ -1,17 +1,17 @@ package dev.restate.sdk.examples.utils; -import dev.restate.sdk.examples.generated.OrderProto; -import dev.restate.sdk.examples.types.Status; +import dev.restate.sdk.examples.generated.OrderProto.*; +import dev.restate.sdk.examples.types.StatusEnum; public class TypeUtils { - public static OrderProto.OrderStatus statusToProto(String id, Status status) { - return OrderProto.OrderStatus.newBuilder() + public static OrderStatus statusToProto(String id, StatusEnum statusEnum) { + return OrderStatus.newBuilder() .setOrderId(id) - .setStatus(OrderProto.Status.valueOf(status.name())) + .setStatus(Status.valueOf(statusEnum.name())) .build(); } - public static OrderProto.OrderId toOrderIdProto(String id) { - return OrderProto.OrderId.newBuilder().setOrderId(id).build(); + public static OrderId toOrderIdProto(String id) { + return OrderId.newBuilder().setOrderId(id).build(); } } diff --git a/java/food-ordering/app/restate-app/src/main/resources/log4j2.properties b/java/food-ordering/app/restate-app/src/main/resources/log4j2.properties index 67f6693e..81a0455a 100644 --- a/java/food-ordering/app/restate-app/src/main/resources/log4j2.properties +++ b/java/food-ordering/app/restate-app/src/main/resources/log4j2.properties @@ -7,6 +7,20 @@ appender.console.name = consoleLogger appender.console.layout.type = PatternLayout appender.console.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %notEmpty{[%X{restateServiceMethod}]}%notEmpty{[%X{restateInvocationId}]} %c - %m%n +# Filter out logging during replay +appender.console.filter.replay.type = ContextMapFilter +appender.console.filter.replay.onMatch = DENY +appender.console.filter.replay.onMismatch = NEUTRAL +appender.console.filter.replay.0.type = KeyValuePair +appender.console.filter.replay.0.key = restateInvocationStatus +appender.console.filter.replay.0.value = REPLAYING + +# Restate logs to debug level +logger.app.name = dev.restate +logger.app.level = info +logger.app.additivity = false +logger.app.appenderRef.console.ref = consoleLogger + # Root logger rootLogger.level = info rootLogger.appenderRef.stdout.ref = consoleLogger \ No newline at end of file diff --git a/java/food-ordering/webui/src/components/Cart/Cart.tsx b/java/food-ordering/webui/src/components/Cart/Cart.tsx index 3eaaefd3..5f76df16 100644 --- a/java/food-ordering/webui/src/components/Cart/Cart.tsx +++ b/java/food-ordering/webui/src/components/Cart/Cart.tsx @@ -66,17 +66,17 @@ const Cart = () => { const generateJsonReq = () => { const productsToSend = products.map((prod) => { return { - product_id: prod.id.toString(), + productId: prod.id.toString(), description: prod.description, quantity: prod.quantity, }; }); return { - order_id: user!.user_id, - restaurant_id: details.restaurant_id, + orderId: user!.user_id, + restaurantId: details.restaurant_id, products: productsToSend, - total_cost: total.totalPrice, - delivery_delay: details.delivery_delay, + totalCost: total.totalPrice, + deliveryDelay: details.delivery_delay, }; };