From 3f9d724eea8f51f7b1299d7abe5ad3b77a5ed133 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lo=C3=AFc=20Ortola?= <contact@loicortola.com>
Date: Sat, 17 May 2025 11:24:36 +0200
Subject: [PATCH] feat: added step-2

---
 .../bakery/kitchen/KitchenWorker.java         |  5 ---
 .../bakery/MakeCookiesApp.java                | 10 +++++
 .../bakery/OrderCookiesApp.java               | 22 +++++++++++
 .../bakery/kitchen/KitchenWorker.java         | 30 +++++++++++++++
 .../bakery/kitchen/KitchenWorkflow.java       | 10 +++++
 .../bakery/kitchen/KitchenWorkflowImpl.java   | 34 +++++++++++++++++
 .../bakery/kitchen/bake/BakeService.java      | 10 +++++
 .../bakery/kitchen/bake/BakeServiceImpl.java  |  8 ++++
 .../bakery/kitchen/batter/BatterService.java  | 10 +++++
 .../kitchen/batter/BatterServiceImpl.java     |  8 ++++
 .../signals/ConsumeSignal.java                |  4 ++
 .../signals/InventoryActivity.java            |  7 ++++
 .../signals/InventoryActivityImpl.java        | 26 +++++++++++++
 .../signals/InventoryWorkflow.java            | 10 +++++
 .../temporalpractice/signals/MSMain.java      | 37 +++++++++++++++++++
 15 files changed, 226 insertions(+), 5 deletions(-)
 create mode 100644 solutions/day1/part-2/temporalpractice/bakery/MakeCookiesApp.java
 create mode 100644 solutions/day1/part-2/temporalpractice/bakery/OrderCookiesApp.java
 create mode 100644 solutions/day1/part-2/temporalpractice/bakery/kitchen/KitchenWorker.java
 create mode 100644 solutions/day1/part-2/temporalpractice/bakery/kitchen/KitchenWorkflow.java
 create mode 100644 solutions/day1/part-2/temporalpractice/bakery/kitchen/KitchenWorkflowImpl.java
 create mode 100644 solutions/day1/part-2/temporalpractice/bakery/kitchen/bake/BakeService.java
 create mode 100644 solutions/day1/part-2/temporalpractice/bakery/kitchen/bake/BakeServiceImpl.java
 create mode 100644 solutions/day1/part-2/temporalpractice/bakery/kitchen/batter/BatterService.java
 create mode 100644 solutions/day1/part-2/temporalpractice/bakery/kitchen/batter/BatterServiceImpl.java
 create mode 100644 solutions/day1/part-2/temporalpractice/signals/ConsumeSignal.java
 create mode 100644 solutions/day1/part-2/temporalpractice/signals/InventoryActivity.java
 create mode 100644 solutions/day1/part-2/temporalpractice/signals/InventoryActivityImpl.java
 create mode 100644 solutions/day1/part-2/temporalpractice/signals/InventoryWorkflow.java
 create mode 100644 solutions/day1/part-2/temporalpractice/signals/MSMain.java

diff --git a/solutions/day1/part-1/temporalpractice/bakery/kitchen/KitchenWorker.java b/solutions/day1/part-1/temporalpractice/bakery/kitchen/KitchenWorker.java
index b61e118..0f982df 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 0000000..2ea7f9b
--- /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 0000000..0639213
--- /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 0000000..b92e5a6
--- /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 0000000..bec377d
--- /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 0000000..529793a
--- /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 0000000..5b6ed8d
--- /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 0000000..6f4a582
--- /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 0000000..e366a46
--- /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 0000000..4a428a0
--- /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 0000000..ea74daf
--- /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 0000000..1645c76
--- /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 0000000..db1105d
--- /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 0000000..f7cfebd
--- /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 0000000..61cdb4a
--- /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));
+                });
+            }
+        }
+    }
+}
-- 
GitLab