Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Java and Kotlin code snippets to all use case pages #437

Merged
merged 10 commits into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import dev.restate.sdk.annotation.Handler;
import dev.restate.sdk.annotation.Service;
import dev.restate.sdk.http.vertx.RestateHttpEndpointBuilder;
import usecases.utils.Permission;

/**
* WARNING: The Services page relies on the line numbers for the code animations Make sure you adapt
Expand Down Expand Up @@ -38,7 +39,7 @@ public void applyRoleUpdate(Context ctx, UpdateRequest req) {
// </mark_3>

// <mark_3>
for (String permission : req.getPermissions()) {
for (Permission permission : req.getPermissions()) {
// </mark_3>
// <mark_1>
ctx.run(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package concepts.services.types;

import usecases.utils.UserRole;

public class SystemA {
public static boolean applyUserRole(String userId, String role) {
public static boolean applyUserRole(String userId, UserRole role) {
return true;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package concepts.services.types;

import usecases.utils.Permission;

public class SystemB {
public static boolean applyPermission(String userId, String permission) {
public static boolean applyPermission(String userId, Permission permission) {
return true;
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package concepts.services.types;

import usecases.utils.Permission;
import usecases.utils.UserRole;

public class UpdateRequest {
private String userId;
private String role;
private String[] permissions;
private UserRole role;
private Permission[] permissions;

public UpdateRequest(String userId, String role, String[] permissions) {
public UpdateRequest(String userId, UserRole role, Permission[] permissions) {
this.userId = userId;
this.role = role;
this.permissions = permissions;
Expand All @@ -15,11 +18,11 @@ public String getUserId() {
return userId;
}

public String getRole() {
public UserRole getRole() {
return role;
}

public String[] getPermissions() {
public Permission[] getPermissions() {
return permissions;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package usecases.asynctasks;

import static usecases.utils.ExampleStubs.aggregate;
import static usecases.utils.ExampleStubs.split;

import com.fasterxml.jackson.core.type.TypeReference;
import dev.restate.sdk.Awaitable;
import dev.restate.sdk.Context;
import dev.restate.sdk.annotation.Handler;
import dev.restate.sdk.annotation.Service;
import dev.restate.sdk.serde.jackson.JacksonSerdes;
import java.util.ArrayList;
import java.util.List;
import usecases.utils.Result;
import usecases.utils.SubTask;
import usecases.utils.SubTaskResult;
import usecases.utils.Task;

// <start_here>
@Service
public class FanOutWorker {

@Handler
public Result run(Context ctx, Task task) {
// Split the task in subtasks
SubTask[] subTasks = ctx.run(JacksonSerdes.of(new TypeReference<>() {}), () -> split(task));

List<Awaitable<?>> resultFutures = new ArrayList<>();
// <mark_1>
for (SubTask subTask : subTasks) {
Awaitable<SubTaskResult> subResultFuture =
FanOutWorkerClient.fromContext(ctx).runSubtask(subTask);
// </mark_1>

resultFutures.add(subResultFuture);
}

// <mark_2>
Awaitable.all(resultFutures).await();

SubTaskResult[] results =
(SubTaskResult[]) resultFutures.stream().map(Awaitable::await).toArray();
// </mark_2>

return aggregate(results);
}

@Handler
public SubTaskResult runSubtask(Context ctx, SubTask subTask) {
// Processing logic goes here ...
// Can be moved to a separate service to scale independently
return new SubTaskResult();
}
}
// <end_here>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package usecases.asynctasks.simple;

import static usecases.utils.ExampleStubs.someHeavyWork;

import dev.restate.sdk.Context;
import dev.restate.sdk.annotation.Handler;
import dev.restate.sdk.annotation.Service;
import usecases.utils.TaskOpts;

// <start_here>
@Service
public class AsyncTaskService {

// <mark_1>
@Handler
public String runTask(Context ctx, TaskOpts params) {
return someHeavyWork(params);
}
// </mark_1>
}
// <end_here>
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package usecases.asynctasks.simple;

import dev.restate.sdk.JsonSerdes;
import dev.restate.sdk.client.CallRequestOptions;
import dev.restate.sdk.client.Client;
import dev.restate.sdk.client.SendResponse;
import usecases.utils.TaskOpts;

// <start_here>
public class TaskSubmitter {

private static final Client rs = Client.connect("http://localhost:8080");

public void submitAndAwaitTasks(TaskOpts taskOpts) {
// <mark_1>
SendResponse handle =
AsyncTaskServiceClient.fromClient(rs)
.send()
.runTask(
taskOpts,
// <mark_2>
CallRequestOptions.DEFAULT.withIdempotency("dQw4w9WgXcQ")
// </mark_2>
);
// </mark_1>

// await the handler's result
// <mark_3>
String result = rs.invocationHandle(handle.getInvocationId(), JsonSerdes.STRING).attach();

// </mark_3>
}
}
// <end_here>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package usecases.asynctasks.synctoasync;

import static usecases.utils.ExampleStubs.*;

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.serde.jackson.JacksonSerdes;
import develop.workflows.Email;
import usecases.utils.URL;

// <start_here>
@Workflow
public class DataPreparationService {

private static final DurablePromiseKey<URL> URL_PROMISE =
DurablePromiseKey.of("url", JacksonSerdes.of(URL.class));

@Workflow
public URL run(WorkflowContext ctx, String userId) {
URL url = ctx.run(JacksonSerdes.of(URL.class), () -> createS3Bucket());
ctx.run(() -> uploadData(url));

ctx.promiseHandle(URL_PROMISE).resolve(url);
return url;
}

@Shared
public void resultAsEmail(SharedWorkflowContext ctx, Email email) {
URL url = ctx.promise(URL_PROMISE).awaitable().await();
ctx.run(() -> sendEmail(url, email));
}
}
// <end_here>
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package usecases.asynctasks.synctoasync;

import dev.restate.sdk.client.Client;
import develop.workflows.Email;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import usecases.asynctasks.synctoasync.DataPreparationServiceClient.IngressClient;

// <start_here>
public class MyClient {

private static final Client rs = Client.connect("http://localhost:8080");

public void downloadData(String userId, Email email) {
// <mark_1>
IngressClient client = DataPreparationServiceClient.fromClient(rs, userId);
// </mark_1>

// <mark_2>
client.submit(userId);
// </mark_2>

try {
// <mark_3>
CompletableFuture.anyOf(client.workflowHandle().attachAsync())
.orTimeout(30, TimeUnit.SECONDS)
.join();
// </mark_3>
// <mark_4>
} catch (Exception e) {
client.resultAsEmail(email);
return;
}
// </mark_4>
// ... process directly ...
}
}
// <end_here>
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package usecases.eventprocessing;

import static usecases.utils.ExampleStubs.send;

import dev.restate.sdk.ObjectContext;
import dev.restate.sdk.annotation.Handler;
import dev.restate.sdk.annotation.VirtualObject;
import dev.restate.sdk.common.StateKey;
import dev.restate.sdk.common.TerminalException;
import dev.restate.sdk.serde.jackson.JacksonSerdes;
import java.time.Duration;
import usecases.utils.UserProfile;

// <start_here>
@VirtualObject
public class ProfileService {

// <mark_1>
private static final StateKey<UserProfile> USER =
StateKey.of("user", JacksonSerdes.of(UserProfile.class));

// </mark_1>

// <mark_2>
@Handler
public void userEvent(ObjectContext ctx, String name) {
// </mark_2>
UserProfile profile = new UserProfile(ctx.key(), name);
// <mark_1>
ctx.set(USER, profile);
// </mark_1>

// <mark_3>
ProfileServiceClient.fromContext(ctx, ctx.key()).send(Duration.ofSeconds(1)).emit();
// </mark_3>
}

// <mark_2>
@Handler
public void featureEvent(ObjectContext ctx, String email) {
// </mark_2>
// <mark_1>
UserProfile user =
ctx.get(USER)
// </mark_1>
.orElseThrow(() -> new TerminalException("No user found"));
user.setEmail(email);
// <mark_1>
ctx.set(USER, user);
// </mark_1>
}

// <mark_2>
@Handler
public void emit(ObjectContext ctx) {
// </mark_2>
// <mark_1>
UserProfile user =
ctx.get(USER)
// </mark_1>
.orElseThrow(() -> new TerminalException("No user found"));

send(ctx.key(), user);
// <mark_1>
ctx.clearAll();
// </mark_1>
}
}
// <end_here>
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package usecases.eventprocessing;

import static usecases.utils.ExampleStubs.*;

import dev.restate.sdk.JsonSerdes;
import dev.restate.sdk.ObjectContext;
import dev.restate.sdk.annotation.Handler;
import dev.restate.sdk.annotation.VirtualObject;
import java.time.Duration;
import usecases.utils.UserUpdate;

// <start_here>
@VirtualObject
public class UserUpdatesService {

// <mark_1>
@Handler
public void updateUserEvent(ObjectContext ctx, UserUpdate event) {
// </mark_1>
// <mark_3>
String userId = ctx.run(JsonSerdes.STRING, () -> updateUserProfile(event.getProfile()));
// </mark_3>

// <mark_4>
while (userId.equals("NOT_READY")) {
// <mark_2>
ctx.sleep(Duration.ofMillis(5000));
// </mark_2>
// <mark_3>
userId = ctx.run(JsonSerdes.STRING, () -> updateUserProfile(event.getProfile()));
// </mark_3>
}

String finalUserId = userId;
// <mark_3>
String roleId =
ctx.run(JsonSerdes.STRING, () -> setUserPermissions(finalUserId, event.getPermissions()));
ctx.run(() -> provisionResources(finalUserId, roleId, event.getResources()));
// </mark_3>
// </mark_4>
}
}
// <end_here>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package usecases.microservices;

import static dev.restate.sdk.client.CallRequestOptions.*;

import dev.restate.sdk.client.Client;

class Config {
public static String RESTATE_URL = "http://localhost:8080";
}

public class Idempotency {

// <start_here>
Client rs = Client.connect(Config.RESTATE_URL);

public void reserveProduct(String productId, String reservationId) {
// <mark_1>
ProductServiceClient.fromClient(rs, productId)
.send()
.reserve(DEFAULT.withIdempotency(reservationId));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use qualified name, it helps understanding this without reading the import:

Suggested change
.reserve(DEFAULT.withIdempotency(reservationId));
.reserve(CallRequestOptions.DEFAULT.withIdempotency(reservationId));

// </mark_1>
}
// <end_here>

}
Loading
Loading