diff --git a/solutions/day1/part-1/temporalpractice/bakery/kitchen/KitchenWorker.java b/solutions/day1/part-1/temporalpractice/bakery/kitchen/KitchenWorker.java index b61e118c73e9ae8c51ff51695acfe01f95ccc629..0f982df7eacb5e75c12af581863b7b229696ea8a 100644 --- a/solutions/day1/part-1/temporalpractice/bakery/kitchen/KitchenWorker.java +++ b/solutions/day1/part-1/temporalpractice/bakery/kitchen/KitchenWorker.java @@ -13,11 +13,6 @@ public class KitchenWorker { // Your key for interacting with the Temporal world. WorkflowClient client = WorkflowClient.newInstance(serviceStub); - WorkflowOptions options = WorkflowOptions.newBuilder() - .setTaskQueue("TheOneAndOnlyQueue") - .setWorkflowId("best-cookie") - .build(); - WorkerFactory factory = WorkerFactory.newInstance(client); Worker worker = factory.newWorker("TheOneAndOnlyQueue"); diff --git a/solutions/day1/part-2/temporalpractice/bakery/MakeCookiesApp.java b/solutions/day1/part-2/temporalpractice/bakery/MakeCookiesApp.java new file mode 100644 index 0000000000000000000000000000000000000000..2ea7f9b217a272ead8530b059fc580bfa77b3a09 --- /dev/null +++ b/solutions/day1/part-2/temporalpractice/bakery/MakeCookiesApp.java @@ -0,0 +1,10 @@ +package io.takima.temporalpractice.bakery; + +import io.takima.temporalpractice.bakery.kitchen.KitchenWorker; + +public class MakeCookiesApp { + public static void main(String[] args) { + // This app should execute the making of all cookies ordered + new KitchenWorker().start(); + } +} diff --git a/solutions/day1/part-2/temporalpractice/bakery/OrderCookiesApp.java b/solutions/day1/part-2/temporalpractice/bakery/OrderCookiesApp.java new file mode 100644 index 0000000000000000000000000000000000000000..06392139739a8a6c7e663190ec84137994809b09 --- /dev/null +++ b/solutions/day1/part-2/temporalpractice/bakery/OrderCookiesApp.java @@ -0,0 +1,22 @@ +package io.takima.temporalpractice.bakery; + +import io.takima.temporalpractice.bakery.kitchen.KitchenWorkflow; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.serviceclient.WorkflowServiceStubs; + +public class OrderCookiesApp { + public static void main(String[] args) { + // This app simulates an order of cookies + // It should call the workflow which makes cookies + WorkflowClient client = WorkflowClient.newInstance(WorkflowServiceStubs.newLocalServiceStubs()); + WorkflowOptions options = WorkflowOptions.newBuilder() + .setTaskQueue("TheOneAndOnlyQueue") + .setWorkflowId("best-cookie") + .build(); + + KitchenWorkflow workflow = client.newWorkflowStub(KitchenWorkflow.class, options); + + workflow.makeCookies(); // Start the Workflow Execution + } +} diff --git a/solutions/day1/part-2/temporalpractice/bakery/kitchen/KitchenWorker.java b/solutions/day1/part-2/temporalpractice/bakery/kitchen/KitchenWorker.java new file mode 100644 index 0000000000000000000000000000000000000000..b92e5a607e982bfd9eb7207c08da8607596c1180 --- /dev/null +++ b/solutions/day1/part-2/temporalpractice/bakery/kitchen/KitchenWorker.java @@ -0,0 +1,30 @@ +package io.takima.temporalpractice.bakery.kitchen; + +import io.takima.temporalpractice.bakery.kitchen.bake.BakeServiceImpl; +import io.takima.temporalpractice.bakery.kitchen.batter.BatterServiceImpl; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerFactory; + +public class KitchenWorker { + public void start() { + // Represents the connection to your local cluster. For now, lets keep it simple + WorkflowServiceStubs serviceStub = WorkflowServiceStubs.newLocalServiceStubs(); + // Your key for interacting with the Temporal world. + WorkflowClient client = WorkflowClient.newInstance(serviceStub); + + WorkerFactory factory = WorkerFactory.newInstance(client); + + Worker worker = factory.newWorker("TheOneAndOnlyQueue"); + + // Register workflows + worker.registerWorkflowImplementationTypes(KitchenWorkflowImpl.class); + // Register activities + worker.registerActivitiesImplementations(new BakeServiceImpl()); + worker.registerActivitiesImplementations(new BatterServiceImpl()); + + factory.start(); + } +} diff --git a/solutions/day1/part-2/temporalpractice/bakery/kitchen/KitchenWorkflow.java b/solutions/day1/part-2/temporalpractice/bakery/kitchen/KitchenWorkflow.java new file mode 100644 index 0000000000000000000000000000000000000000..bec377d5f138a90d7fd79f430a2f7880697ade48 --- /dev/null +++ b/solutions/day1/part-2/temporalpractice/bakery/kitchen/KitchenWorkflow.java @@ -0,0 +1,10 @@ +package io.takima.temporalpractice.bakery.kitchen; + +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; + +@WorkflowInterface +public interface KitchenWorkflow { + @WorkflowMethod + void makeCookies(); +} diff --git a/solutions/day1/part-2/temporalpractice/bakery/kitchen/KitchenWorkflowImpl.java b/solutions/day1/part-2/temporalpractice/bakery/kitchen/KitchenWorkflowImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..529793a0698ac3b8fb3eec68e752c4e917a04141 --- /dev/null +++ b/solutions/day1/part-2/temporalpractice/bakery/kitchen/KitchenWorkflowImpl.java @@ -0,0 +1,34 @@ +package io.takima.temporalpractice.bakery.kitchen; + +import io.takima.temporalpractice.bakery.kitchen.bake.BakeService; +import io.takima.temporalpractice.bakery.kitchen.batter.BatterService; +import io.temporal.activity.ActivityOptions; +import io.temporal.workflow.Workflow; + +import java.time.Duration; + +public class KitchenWorkflowImpl implements KitchenWorkflow { + private final BatterService batterService; + private final BakeService bakeService; + + public KitchenWorkflowImpl() { + ActivityOptions options = ActivityOptions.newBuilder() + .setTaskQueue("TheOneAndOnlyQueue") + .setStartToCloseTimeout(Duration.ofSeconds(10)) + .build(); + + this.batterService = Workflow.newActivityStub(BatterService.class, options); + this.bakeService = Workflow.newActivityStub(BakeService.class, options); + } + + + @Override + public void makeCookies() { + // Note: System.out.println is used here for simplicity + // In real applications, you should use proper Workflow-aware logging (we'll cover this in Day 2) + System.out.println("Starting to prepare your cookie!"); + batterService.prepareBatter(); + bakeService.bake(); + System.out.println("Your cookie is ready!"); + } +} diff --git a/solutions/day1/part-2/temporalpractice/bakery/kitchen/bake/BakeService.java b/solutions/day1/part-2/temporalpractice/bakery/kitchen/bake/BakeService.java new file mode 100644 index 0000000000000000000000000000000000000000..5b6ed8dd7e17c8db7affd2536b51845290ae7ece --- /dev/null +++ b/solutions/day1/part-2/temporalpractice/bakery/kitchen/bake/BakeService.java @@ -0,0 +1,10 @@ +package io.takima.temporalpractice.bakery.kitchen.bake; + +import io.temporal.activity.ActivityInterface; +import io.temporal.activity.ActivityMethod; + +@ActivityInterface +public interface BakeService { + @ActivityMethod + void bake(); +} diff --git a/solutions/day1/part-2/temporalpractice/bakery/kitchen/bake/BakeServiceImpl.java b/solutions/day1/part-2/temporalpractice/bakery/kitchen/bake/BakeServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..6f4a58237f3c22e714735bd1511ed1e97148d48f --- /dev/null +++ b/solutions/day1/part-2/temporalpractice/bakery/kitchen/bake/BakeServiceImpl.java @@ -0,0 +1,8 @@ +package io.takima.temporalpractice.bakery.kitchen.bake; + +public class BakeServiceImpl implements BakeService { + @Override + public void bake() { + System.out.println("Now baking those cookies."); + } +} diff --git a/solutions/day1/part-2/temporalpractice/bakery/kitchen/batter/BatterService.java b/solutions/day1/part-2/temporalpractice/bakery/kitchen/batter/BatterService.java new file mode 100644 index 0000000000000000000000000000000000000000..e366a467a8ece5ff86a03dfbbb50c4c3a6dd9d71 --- /dev/null +++ b/solutions/day1/part-2/temporalpractice/bakery/kitchen/batter/BatterService.java @@ -0,0 +1,10 @@ +package io.takima.temporalpractice.bakery.kitchen.batter; + +import io.temporal.activity.ActivityInterface; +import io.temporal.activity.ActivityMethod; + +@ActivityInterface +public interface BatterService { + @ActivityMethod + void prepareBatter(); +} diff --git a/solutions/day1/part-2/temporalpractice/bakery/kitchen/batter/BatterServiceImpl.java b/solutions/day1/part-2/temporalpractice/bakery/kitchen/batter/BatterServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..4a428a085ea4341aaf7e3b58e45cd696ead18aae --- /dev/null +++ b/solutions/day1/part-2/temporalpractice/bakery/kitchen/batter/BatterServiceImpl.java @@ -0,0 +1,8 @@ +package io.takima.temporalpractice.bakery.kitchen.batter; + +public class BatterServiceImpl implements BatterService { + @Override + public void prepareBatter() { + System.out.println("Mixing flour, sugar, and love..."); + } +} diff --git a/solutions/day1/part-2/temporalpractice/signals/ConsumeSignal.java b/solutions/day1/part-2/temporalpractice/signals/ConsumeSignal.java new file mode 100644 index 0000000000000000000000000000000000000000..ea74daf4991015ae277c287aa2402193e24eaee9 --- /dev/null +++ b/solutions/day1/part-2/temporalpractice/signals/ConsumeSignal.java @@ -0,0 +1,4 @@ +package io.takima.temporalpractice.signals; + +public record ConsumeSignal(int amount) { +} diff --git a/solutions/day1/part-2/temporalpractice/signals/InventoryActivity.java b/solutions/day1/part-2/temporalpractice/signals/InventoryActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..1645c7643195d369993ec1375c8de52c6fa856ad --- /dev/null +++ b/solutions/day1/part-2/temporalpractice/signals/InventoryActivity.java @@ -0,0 +1,7 @@ +package io.takima.temporalpractice.signals; +// TODO : remove comments when starting the mastering signals exercise on day 2 +//@ActivityInterface +public interface InventoryActivity { + void reserve(ConsumeSignal input); + +} diff --git a/solutions/day1/part-2/temporalpractice/signals/InventoryActivityImpl.java b/solutions/day1/part-2/temporalpractice/signals/InventoryActivityImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..db1105d9751e2a4be98e0240afbf2f94065bc38d --- /dev/null +++ b/solutions/day1/part-2/temporalpractice/signals/InventoryActivityImpl.java @@ -0,0 +1,26 @@ +package io.takima.temporalpractice.signals; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class InventoryActivityImpl implements InventoryActivity { + private static final Logger logger = LoggerFactory.getLogger(InventoryActivityImpl.class); + int counter; + + public InventoryActivityImpl(int inventorySize){ + this.counter = inventorySize; + } + + @Override + public void reserve(ConsumeSignal input) { + int currentValue = counter; + + try { + //Simulate async work + Thread.sleep(10); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + counter = currentValue - 1; + logger.info("counter: " + counter); + } +} diff --git a/solutions/day1/part-2/temporalpractice/signals/InventoryWorkflow.java b/solutions/day1/part-2/temporalpractice/signals/InventoryWorkflow.java new file mode 100644 index 0000000000000000000000000000000000000000..f7cfebd14e18d650c4f9266a5a9ba9c91bcb39b5 --- /dev/null +++ b/solutions/day1/part-2/temporalpractice/signals/InventoryWorkflow.java @@ -0,0 +1,10 @@ +package io.takima.temporalpractice.signals; +// TODO : remove comments when starting the mastering signals exercise on day 2 +//@WorkflowInterface +public interface InventoryWorkflow { +// @WorkflowMethod + void run(); +// @SignalMethod + void reserve(ConsumeSignal input); + +} diff --git a/solutions/day1/part-2/temporalpractice/signals/MSMain.java b/solutions/day1/part-2/temporalpractice/signals/MSMain.java new file mode 100644 index 0000000000000000000000000000000000000000..61cdb4ac225a3fd9336a9ac633871b0542daf3b4 --- /dev/null +++ b/solutions/day1/part-2/temporalpractice/signals/MSMain.java @@ -0,0 +1,37 @@ +package io.takima.temporalpractice.signals; +// TODO : remove comments when starting the mastering signals exercise on day 2 +//import io.temporal.client.WorkflowClient; +//import io.temporal.client.WorkflowOptions; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +//import static io.takima.temporalpractice.temporal.TemporalUtils.*; +//import static io.takima.temporalpractice.temporal.TemporalQueues.*; +public class MSMain { + + // Our inventory will contain 100 elements and we will send 100 signals, lets see how it goes + static int inventoryToDecrement = 100; + + public static void main(String[] args) { +// var worker = FACTORY.newWorker(MASTERING_SIGNALS); +// worker.registerActivitiesImplementations(new InventoryActivityImpl(inventoryToDecrement)); +// worker.registerWorkflowImplementationTypes(InventoryWorkflowImpl.class); + +// FACTORY.start(); + +// var workflow = CLIENT.newWorkflowStub( +// InventoryWorkflow.class, +// WorkflowOptions.newBuilder().setTaskQueue(MASTERING_SIGNALS).setWorkflowId("inventory").build() +// ); +// WorkflowClient.start(workflow::run); + try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) { + // Submit 100 tasks + for (int i = 1; i < inventoryToDecrement; i++) { + executor.submit(() -> { +// workflow.reserve(new ConsumeSignal(1)); + }); + } + } + } +}