Skip to content

Commit

Permalink
Add Java workflows basics (#174)
Browse files Browse the repository at this point in the history
* Add Java workflows basics

* Fix bug in TS workflow
  • Loading branch information
gvdongen authored Jul 25, 2024
1 parent dc65b67 commit 42c1d15
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 3 deletions.
5 changes: 5 additions & 0 deletions basics/basics-java/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ about how they work and how they can be run.
./gradlew -PmainClass=durable_execution_compensation.RoleUpdateService run
```

* **[Workflows](workflows/SignupWorkflow.java):** Workflows are durable execution tasks that can
be submitted and awaited. They have an identity and can be signaled and queried
through durable promises. The example is a user-signup flow that takes multiple
operations, including verifying the email address.

* **[Virtual Objects](virtual_objects/GreeterObject.java):** Stateful serverless objects
to manage durable consistent state and state-manipulating logic.
```shell
Expand Down
5 changes: 5 additions & 0 deletions basics/basics-java/src/main/java/utils/ExampleStubs.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,9 @@ public static String setUserPermissions(String userId, String permissions) {

public static void provisionResources(String userId, String role, String resources){}

public static void createUserEntry(User user){

}
public static void sendEmailWithLink(String email, String secret){
}
}
31 changes: 31 additions & 0 deletions basics/basics-java/src/main/java/utils/User.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package utils;

public class User {

private String name;
private String email;

public User(
String email,
String name
){
this.email = email;
this.name = name;
}

public String getEmail() {
return email;
}

public String getName() {
return name;
}

public void setEmail(String email) {
this.email = email;
}

public void setName(String name) {
this.name = name;
}
}
89 changes: 89 additions & 0 deletions basics/basics-java/src/main/java/workflows/SignupWorkflow.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright (c) 2024 - Restate Software, Inc., Restate GmbH
*
* This file is part of the Restate Examples for the Node.js/TypeScript SDK,
* which is released under the MIT license.
*
* You can find a copy of the license in the file LICENSE
* in the root directory of this repository or package or at
* https://github.com/restatedev/examples/blob/main/LICENSE
*/
package workflows;

import dev.restate.sdk.JsonSerdes;
import dev.restate.sdk.SharedWorkflowContext;
import dev.restate.sdk.WorkflowContext;
import dev.restate.sdk.annotation.Shared;
import dev.restate.sdk.annotation.Workflow;
import dev.restate.sdk.common.DurablePromiseKey;
import dev.restate.sdk.common.StateKey;
import dev.restate.sdk.http.vertx.RestateHttpEndpointBuilder;
import utils.User;

import static utils.ExampleStubs.createUserEntry;
import static utils.ExampleStubs.sendEmailWithLink;

//
// A simple workflow for a user signup and email verification.
//
// - the main workflow is in the run() method
// - any number of other methods can be added to implement interactions
// with the workflow.
//
// Workflow instances always have a unique ID that identifies the workflow execution.
// Each workflow instance (ID) can run only once (to success or failure).
//
@Workflow
public class SignupWorkflow {

// References to K/V state and promises stored in Restate
private static final DurablePromiseKey<String> EMAIL_CLICKED =
DurablePromiseKey.of("email_clicked", JsonSerdes.STRING);
private static final StateKey<String> ONBOARDING_STATUS =
StateKey.of("status", JsonSerdes.STRING);

@Workflow
public boolean run(WorkflowContext ctx, User user) {

// Durably executed action; write to other system
ctx.run(() -> createUserEntry(user));

// Store some K/V state; can be retrieved from other handlers
ctx.set(ONBOARDING_STATUS, "Created user");

// Sent user email with verification link
String secret = ctx.random().nextUUID().toString();
ctx.run(() -> sendEmailWithLink(user.getEmail(), secret));
ctx.set(ONBOARDING_STATUS, "Verifying user");

// Wait until user clicked email verification link
// Resolved or rejected by the other handlers
String clickSecret =
ctx.promise(EMAIL_CLICKED)
.awaitable()
.await();
ctx.set(ONBOARDING_STATUS, "Link clicked");

return clickSecret.equals(secret);
}


@Shared
public void click(SharedWorkflowContext ctx, String secret) {
// Resolve the promise with the result secret
ctx.promiseHandle(EMAIL_CLICKED).resolve(secret);
}

@Shared
public String getStatus(SharedWorkflowContext ctx) {
// Get the onboarding status of the user
return ctx.get(ONBOARDING_STATUS).orElse("Unknown");
}


public static void main(String[] args) {
RestateHttpEndpointBuilder.builder()
.bind(new SignupWorkflow())
.buildAndListen();
}
}
4 changes: 2 additions & 2 deletions basics/basics-typescript/src/3_workflows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ const myWorkflow = restate.workflow({
ctx.set("stage", "Creating User");

// use all the standard durable execution features here
await ctx.run(() => createUserEntry({userId, name}));
await ctx.run(() => createUserEntry({name, email}));

ctx.set("stage", "Email Verification");

// send the email with the verification secret
const secret = await ctx.run(() => crypto.randomUUID());
const secret = ctx.rand.uuidv4();
ctx.run(() => sendEmailWithLink({email, secret}));

try {
Expand Down
2 changes: 1 addition & 1 deletion basics/basics-typescript/src/utils/workflow_stubs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@
* https://github.com/restatedev/examples/blob/main/LICENSE
*/

export async function createUserEntry(entry: { userId: string; name: string }) {}
export async function createUserEntry(entry: { name: string, email: string }) {}

export async function sendEmailWithLink(details: { email: string; secret: string }) {}

0 comments on commit 42c1d15

Please sign in to comment.