Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
@@ -0,0 +1,80 @@
// Copyright (c) 2023 - Restate Software, Inc., Restate GmbH
//
// This file is part of the Restate Java SDK,
// which is released under the MIT license.
//
// You can find a copy of the license in file LICENSE in the root
// directory of this repository or package, or at
// https://github.com/restatedev/sdk-java/blob/main/LICENSE
package dev.restate.sdk.springboot.java;

import static org.assertj.core.api.Assertions.*;

import com.fasterxml.jackson.databind.ObjectMapper;
import dev.restate.sdk.core.generated.manifest.EndpointManifestSchema;
import dev.restate.sdk.springboot.RestateEndpointConfiguration;
import dev.restate.sdk.springboot.RestateHttpConfiguration;
import dev.restate.sdk.springboot.RestateHttpEndpointBean;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest(
classes = {
RestateEndpointConfiguration.class,
RestateHttpConfiguration.class,
Greeter.class,
GreeterNewApi.class,
ServicesConfiguration.class
},
properties = {
"restate.sdk.http.port=0",
// Default applied to both services
"restate.journal-retention=PT48H",
// Per-service override for greeterNewApi
"restate.components.greeterNewApi.journal-retention=PT72H",
"greetingPrefix=Hello "
})
public class RestateHttpEndpointBeanDefaultsTest {

@Autowired private RestateHttpEndpointBean restateHttpEndpointBean;

@Test
public void defaultConfigShouldApplyToAllServicesAndPerServiceOverrideWins()
throws IOException, InterruptedException {
assertThat(restateHttpEndpointBean.isRunning()).isTrue();

var client = HttpClient.newBuilder().version(HttpClient.Version.HTTP_2).build();
var response =
client.send(
HttpRequest.newBuilder()
.GET()
.version(HttpClient.Version.HTTP_2)
.uri(
URI.create(
"http://localhost:" + restateHttpEndpointBean.actualPort() + "/discover"))
.header("Accept", "application/vnd.restate.endpointmanifest.v4+json")
.build(),
HttpResponse.BodyHandlers.ofString());
assertThat(response.statusCode()).isEqualTo(200);

var endpointManifest =
new ObjectMapper().readValue(response.body(), EndpointManifestSchema.class);

assertThat(endpointManifest.getServices())
.extracting(
dev.restate.sdk.core.generated.manifest.Service::getName,
dev.restate.sdk.core.generated.manifest.Service::getJournalRetention)
.containsExactlyInAnyOrder(
// greeter gets the global default
tuple("greeter", Duration.ofHours(48).toMillis()),
// greeterNewApi gets its per-service override
tuple("greeterNewApi", Duration.ofHours(72).toMillis()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
// https://github.com/restatedev/sdk-java/blob/main/LICENSE
package dev.restate.sdk.springboot;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import org.jspecify.annotations.Nullable;
Expand All @@ -16,12 +17,21 @@
/**
* Properties for configuring Restate services.
*
* <p>Top-level fields (e.g. {@code restate.inactivity-timeout}) act as defaults applied to all
* services. Per-service configuration in {@link #getComponents()} takes precedence over these
* defaults.
*
* <p>Example configuration in {@code application.properties}:
*
* <pre>{@code
* # Configuration for a service named "MyService"
* # Default configuration applied to all services
* restate.executor=myGlobalExecutor
* restate.inactivity-timeout=10m
* restate.retry-policy.max-attempts=5
*
* # Per-service configuration (overrides defaults)
* restate.components.MyService.executor=myServiceExecutor
* restate.components.MyService.inactivity-timeout=10m
* restate.components.MyService.inactivity-timeout=5m
* restate.components.MyService.abort-timeout=1m
* restate.components.MyService.idempotency-retention=1d
* restate.components.MyService.journal-retention=7d
Expand All @@ -47,14 +57,23 @@
public class RestateComponentsProperties {

@Nullable private String executor;
@Nullable private String documentation;
@Nullable private Map<String, String> metadata;
@Nullable private Duration inactivityTimeout;
@Nullable private Duration abortTimeout;
@Nullable private Duration idempotencyRetention;
@Nullable private Duration workflowRetention;
@Nullable private Duration journalRetention;
@Nullable private Boolean ingressPrivate;
@Nullable private Boolean enableLazyState;
@Nullable private RetryPolicyProperties retryPolicy;

// Map keyed by function bean name (e.g. restate.function.my-function.inactivity-timeout)
// Map keyed by service name (e.g. restate.components.MyService.inactivity-timeout)
private Map<String, RestateComponentProperties> components = new HashMap<>();

/**
* Name of the {@link java.util.concurrent.Executor} bean to use for running handlers of all
* services. This is the global default and can be overridden per-service in {@link
* #getComponents()}.
* services. Can be overridden per-service in {@link #getComponents()}.
*
* <p><b>NOTE:</b> This option is only used for Java services, not Kotlin services.
*
Expand All @@ -68,8 +87,7 @@ public class RestateComponentsProperties {

/**
* Name of the {@link java.util.concurrent.Executor} bean to use for running handlers of all
* services. This is the global default and can be overridden per-service in {@link
* #getComponents()}.
* services. Can be overridden per-service in {@link #getComponents()}.
*
* <p><b>NOTE:</b> This option is only used for Java services, not Kotlin services.
*
Expand All @@ -82,7 +100,231 @@ public void setExecutor(@Nullable String executor) {
}

/**
* Per-component configuration, keyed by component/service name.
* Default documentation for all services, as shown in the UI, Admin REST API, and the generated
* OpenAPI documentation. Can be overridden per-service in {@link #getComponents()}.
*/
public @Nullable String getDocumentation() {
return documentation;
}

/**
* Default documentation for all services, as shown in the UI, Admin REST API, and the generated
* OpenAPI documentation. Can be overridden per-service in {@link #getComponents()}.
*/
public void setDocumentation(@Nullable String documentation) {
this.documentation = documentation;
}

/**
* Default metadata for all services, as propagated in the Admin REST API. Can be overridden
* per-service in {@link #getComponents()}.
*/
public @Nullable Map<String, String> getMetadata() {
return metadata;
}

/**
* Default metadata for all services, as propagated in the Admin REST API. Can be overridden
* per-service in {@link #getComponents()}.
*/
public void setMetadata(@Nullable Map<String, String> metadata) {
this.metadata = metadata;
}

/**
* Default inactivity timeout for all services. Can be overridden per-service in {@link
* #getComponents()}.
*
* <p><b>NOTE:</b> You can set this field only if you register services against restate-server >=
* 1.4, otherwise service discovery will fail.
*
* @see RestateComponentProperties#getInactivityTimeout()
*/
public @Nullable Duration getInactivityTimeout() {
return inactivityTimeout;
}

/**
* Default inactivity timeout for all services. Can be overridden per-service in {@link
* #getComponents()}.
*
* <p><b>NOTE:</b> You can set this field only if you register services against restate-server >=
* 1.4, otherwise service discovery will fail.
*/
public void setInactivityTimeout(@Nullable Duration inactivityTimeout) {
this.inactivityTimeout = inactivityTimeout;
}

/**
* Default abort timeout for all services. Can be overridden per-service in {@link
* #getComponents()}.
*
* <p><b>NOTE:</b> You can set this field only if you register services against restate-server >=
* 1.4, otherwise service discovery will fail.
*
* @see RestateComponentProperties#getAbortTimeout()
*/
public @Nullable Duration getAbortTimeout() {
return abortTimeout;
}

/**
* Default abort timeout for all services. Can be overridden per-service in {@link
* #getComponents()}.
*
* <p><b>NOTE:</b> You can set this field only if you register services against restate-server >=
* 1.4, otherwise service discovery will fail.
*/
public void setAbortTimeout(@Nullable Duration abortTimeout) {
this.abortTimeout = abortTimeout;
}

/**
* Default idempotency retention for all services. Can be overridden per-service in {@link
* #getComponents()}.
*
* <p><b>NOTE:</b> You can set this field only if you register services against restate-server >=
* 1.4, otherwise service discovery will fail.
*
* @see RestateComponentProperties#getIdempotencyRetention()
*/
public @Nullable Duration getIdempotencyRetention() {
return idempotencyRetention;
}

/**
* Default idempotency retention for all services. Can be overridden per-service in {@link
* #getComponents()}.
*
* <p><b>NOTE:</b> You can set this field only if you register services against restate-server >=
* 1.4, otherwise service discovery will fail.
*/
public void setIdempotencyRetention(@Nullable Duration idempotencyRetention) {
this.idempotencyRetention = idempotencyRetention;
}

/**
* Default workflow retention for all workflow services. Can be overridden per-service in {@link
* #getComponents()}.
*
* <p><b>NOTE:</b> You can set this field only if you register services against restate-server >=
* 1.4, otherwise service discovery will fail.
*
* @see RestateComponentProperties#getWorkflowRetention()
*/
public @Nullable Duration getWorkflowRetention() {
return workflowRetention;
}

/**
* Default workflow retention for all workflow services. Can be overridden per-service in {@link
* #getComponents()}.
*
* <p><b>NOTE:</b> You can set this field only if you register services against restate-server >=
* 1.4, otherwise service discovery will fail.
*/
public void setWorkflowRetention(@Nullable Duration workflowRetention) {
this.workflowRetention = workflowRetention;
}

/**
* Default journal retention for all services. Can be overridden per-service in {@link
* #getComponents()}.
*
* <p><b>NOTE:</b> You can set this field only if you register services against restate-server >=
* 1.4, otherwise service discovery will fail.
*
* @see RestateComponentProperties#getJournalRetention()
*/
public @Nullable Duration getJournalRetention() {
return journalRetention;
}

/**
* Default journal retention for all services. Can be overridden per-service in {@link
* #getComponents()}.
*
* <p><b>NOTE:</b> You can set this field only if you register services against restate-server >=
* 1.4, otherwise service discovery will fail.
*/
public void setJournalRetention(@Nullable Duration journalRetention) {
this.journalRetention = journalRetention;
}

/**
* Default ingress-private setting for all services. Can be overridden per-service in {@link
* #getComponents()}.
*
* <p><b>NOTE:</b> You can set this field only if you register services against restate-server >=
* 1.4, otherwise service discovery will fail.
*
* @see RestateComponentProperties#getIngressPrivate()
*/
public @Nullable Boolean getIngressPrivate() {
return ingressPrivate;
}

/**
* Default ingress-private setting for all services. Can be overridden per-service in {@link
* #getComponents()}.
*
* <p><b>NOTE:</b> You can set this field only if you register services against restate-server >=
* 1.4, otherwise service discovery will fail.
*/
public void setIngressPrivate(@Nullable Boolean ingressPrivate) {
this.ingressPrivate = ingressPrivate;
}

/**
* Default lazy-state setting for all services. Can be overridden per-service in {@link
* #getComponents()}.
*
* <p><b>NOTE:</b> You can set this field only if you register services against restate-server >=
* 1.4, otherwise service discovery will fail.
*
* @see RestateComponentProperties#getEnableLazyState()
*/
public @Nullable Boolean getEnableLazyState() {
return enableLazyState;
}

/**
* Default lazy-state setting for all services. Can be overridden per-service in {@link
* #getComponents()}.
*
* <p><b>NOTE:</b> You can set this field only if you register services against restate-server >=
* 1.4, otherwise service discovery will fail.
*/
public void setEnableLazyState(@Nullable Boolean enableLazyState) {
this.enableLazyState = enableLazyState;
}

/**
* Default retry policy for all services. Can be overridden per-service in {@link
* #getComponents()}.
*
* <p><b>NOTE:</b> You can set this field only if you register services against restate-server >=
* 1.5, otherwise service discovery will fail.
*
* @see RestateComponentProperties#getRetryPolicy()
*/
public @Nullable RetryPolicyProperties getRetryPolicy() {
return retryPolicy;
}

/**
* Default retry policy for all services. Can be overridden per-service in {@link
* #getComponents()}.
*
* <p><b>NOTE:</b> You can set this field only if you register services against restate-server >=
* 1.5, otherwise service discovery will fail.
*/
public void setRetryPolicy(@Nullable RetryPolicyProperties retryPolicy) {
this.retryPolicy = retryPolicy;
}

/**
* Per-component configuration, keyed by component/service name. Overrides any top-level defaults.
*
* <p>Example configuration in {@code application.properties}:
*
Expand All @@ -96,7 +338,7 @@ public Map<String, RestateComponentProperties> getComponents() {
}

/**
* Per-component configuration, keyed by component/service name.
* Per-component configuration, keyed by component/service name. Overrides any top-level defaults.
*
* <p>Example configuration in {@code application.properties}:
*
Expand Down
Loading
Loading