Skip to content

Commit 125ba54

Browse files
committed
env config sample
1 parent 626bf03 commit 125ba54

File tree

6 files changed

+230
-0
lines changed

6 files changed

+230
-0
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ See the README.md file in each main sample directory for cut/paste Gradle comman
112112

113113
- [**Worker Versioning**](/core/src/main/java/io/temporal/samples/workerversioning): Demonstrates how to use worker versioning to manage workflow code changes.
114114

115+
- [**Environment Configuration**](/core/src/main/java/io/temporal/samples/envconfig):
116+
Load client configuration from TOML files with programmatic overrides.
117+
115118
#### API demonstrations
116119

117120
- [**Async Untyped Child Workflow**](/core/src/main/java/io/temporal/samples/asyncuntypedchild): Demonstrates how to invoke an untyped child workflow async, that can complete after parent workflow is already completed.

core/build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ dependencies {
44
implementation "io.temporal:temporal-opentracing:$javaSDKVersion"
55
testImplementation("io.temporal:temporal-testing:$javaSDKVersion")
66

7+
// Environment configuration
8+
implementation "io.temporal:temporal-envconfig"
9+
710
// Needed for SDK related functionality
811
implementation(platform("com.fasterxml.jackson:jackson-bom:2.17.2"))
912
implementation "com.fasterxml.jackson.core:jackson-databind"
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package io.temporal.samples.envconfig;
2+
3+
import io.temporal.client.WorkflowClient;
4+
import io.temporal.client.WorkflowClientOptions;
5+
import io.temporal.envconfig.ClientConfigProfile;
6+
import io.temporal.envconfig.LoadClientConfigProfileOptions;
7+
import io.temporal.serviceclient.WorkflowServiceStubs;
8+
import io.temporal.serviceclient.WorkflowServiceStubsOptions;
9+
import java.nio.file.Paths;
10+
import org.slf4j.Logger;
11+
import org.slf4j.LoggerFactory;
12+
13+
/**
14+
* This sample demonstrates loading the default environment configuration profile from a TOML file.
15+
*/
16+
public class LoadFromFile {
17+
18+
private static final Logger logger = LoggerFactory.getLogger(LoadFromFile.class);
19+
20+
public static void main(String[] args) {
21+
try {
22+
// For this sample to be self-contained, we explicitly provide the path to
23+
// the config.toml file included in this directory.
24+
// By default though, the config.toml file will be loaded from
25+
// ~/.config/temporal/temporal.toml (or the equivalent standard config directory on your OS).
26+
String configFilePath =
27+
Paths.get(LoadFromFile.class.getResource("/config.toml").toURI()).toString();
28+
29+
logger.info("--- Loading 'default' profile from {} ---", configFilePath);
30+
31+
// Load client profile from file. By default, this loads the "default" profile
32+
// and applies any environment variable overrides.
33+
ClientConfigProfile profile =
34+
ClientConfigProfile.load(
35+
LoadClientConfigProfileOptions.newBuilder()
36+
.setConfigFilePath(configFilePath)
37+
.build());
38+
39+
// Convert profile to client options (equivalent to Python's load_client_connect_config)
40+
WorkflowServiceStubsOptions serviceStubsOptions = profile.toWorkflowServiceStubsOptions();
41+
WorkflowClientOptions clientOptions = profile.toWorkflowClientOptions();
42+
43+
logger.info("Loaded 'default' profile from {}", configFilePath);
44+
logger.info(" Address: {}", serviceStubsOptions.getTarget());
45+
logger.info(" Namespace: {}", clientOptions.getNamespace());
46+
if (serviceStubsOptions.getHeaders() != null
47+
&& !serviceStubsOptions.getHeaders().keys().isEmpty()) {
48+
logger.info(" gRPC Metadata keys: {}", serviceStubsOptions.getHeaders().keys());
49+
}
50+
51+
logger.info("\nAttempting to connect to client...");
52+
53+
try {
54+
// Create the workflow client using the loaded configuration
55+
WorkflowClient client =
56+
WorkflowClient.newInstance(
57+
WorkflowServiceStubs.newServiceStubs(serviceStubsOptions), clientOptions);
58+
59+
// Test the connection by getting system info
60+
var systemInfo =
61+
client
62+
.getWorkflowServiceStubs()
63+
.blockingStub()
64+
.getSystemInfo(
65+
io.temporal.api.workflowservice.v1.GetSystemInfoRequest.getDefaultInstance());
66+
67+
logger.info("✅ Client connected successfully!");
68+
logger.info(" Server version: {}", systemInfo.getServerVersion());
69+
70+
} catch (Exception e) {
71+
logger.error("❌ Failed to connect: {}", e.getMessage());
72+
}
73+
74+
} catch (Exception e) {
75+
logger.error("Failed to load configuration: {}", e.getMessage(), e);
76+
System.exit(1);
77+
}
78+
}
79+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package io.temporal.samples.envconfig;
2+
3+
import io.temporal.client.WorkflowClient;
4+
import io.temporal.client.WorkflowClientOptions;
5+
import io.temporal.envconfig.ClientConfigProfile;
6+
import io.temporal.envconfig.LoadClientConfigProfileOptions;
7+
import io.temporal.serviceclient.WorkflowServiceStubs;
8+
import io.temporal.serviceclient.WorkflowServiceStubsOptions;
9+
import java.nio.file.Paths;
10+
import org.slf4j.Logger;
11+
import org.slf4j.LoggerFactory;
12+
13+
/**
14+
* This sample demonstrates loading a specific profile from a TOML configuration file with
15+
* programmatic overrides.
16+
*/
17+
public class LoadProfile {
18+
19+
private static final Logger logger = LoggerFactory.getLogger(LoadProfile.class);
20+
21+
public static void main(String[] args) {
22+
String profileName = "staging";
23+
24+
try {
25+
// For this sample to be self-contained, we explicitly provide the path to
26+
// the config.toml file included in this directory.
27+
String configFilePath =
28+
Paths.get(LoadProfile.class.getResource("/config.toml").toURI()).toString();
29+
30+
logger.info("--- Loading '{}' profile from {} ---", profileName, configFilePath);
31+
32+
// Load specific profile from file with environment variable overrides
33+
ClientConfigProfile profile =
34+
ClientConfigProfile.load(
35+
LoadClientConfigProfileOptions.newBuilder()
36+
.setConfigFilePath(configFilePath)
37+
.setConfigFileProfile(profileName)
38+
.build());
39+
40+
// Demonstrate programmatic override - fix the incorrect address from staging profile
41+
logger.info("\n--- Applying programmatic override ---");
42+
ClientConfigProfile.Builder profileBuilder = profile.toBuilder();
43+
profileBuilder.setAddress("localhost:7233"); // Override the incorrect address
44+
profile = profileBuilder.build();
45+
logger.info(" Overridden address to: {}", profile.getAddress());
46+
47+
// Convert profile to client options (equivalent to Python's load_client_connect_config)
48+
WorkflowServiceStubsOptions serviceStubsOptions = profile.toWorkflowServiceStubsOptions();
49+
WorkflowClientOptions clientOptions = profile.toWorkflowClientOptions();
50+
51+
logger.info("Loaded '{}' profile from {}", profileName, configFilePath);
52+
logger.info(" Address: {}", serviceStubsOptions.getTarget());
53+
logger.info(" Namespace: {}", clientOptions.getNamespace());
54+
if (serviceStubsOptions.getHeaders() != null
55+
&& !serviceStubsOptions.getHeaders().keys().isEmpty()) {
56+
logger.info(" gRPC Metadata keys: {}", serviceStubsOptions.getHeaders().keys());
57+
}
58+
59+
logger.info("\nAttempting to connect to client...");
60+
61+
try {
62+
// Create the workflow client using the loaded configuration
63+
WorkflowClient client =
64+
WorkflowClient.newInstance(
65+
WorkflowServiceStubs.newServiceStubs(serviceStubsOptions), clientOptions);
66+
67+
// Test the connection by getting system info
68+
var systemInfo =
69+
client
70+
.getWorkflowServiceStubs()
71+
.blockingStub()
72+
.getSystemInfo(
73+
io.temporal.api.workflowservice.v1.GetSystemInfoRequest.getDefaultInstance());
74+
75+
logger.info("✅ Client connected successfully!");
76+
logger.info(" Server version: {}", systemInfo.getServerVersion());
77+
78+
} catch (Exception e) {
79+
logger.error("❌ Failed to connect: {}", e.getMessage());
80+
}
81+
82+
} catch (Exception e) {
83+
logger.error("Failed to load configuration: {}", e.getMessage(), e);
84+
System.exit(1);
85+
}
86+
}
87+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Environment Configuration Sample
2+
3+
This sample demonstrates how to configure a Temporal client using TOML configuration files. This allows you to manage connection settings across different environments without hardcoding them.
4+
5+
The `config.toml` file defines three profiles:
6+
- `[profile.default]`: Local development configuration
7+
- `[profile.staging]`: Configuration with incorrect address to demonstrate overrides
8+
- `[profile.prod]`: Example production configuration (not runnable)
9+
10+
**Load from file (default profile):**
11+
```bash
12+
./gradlew -q execute -PmainClass=io.temporal.samples.envconfig.LoadFromFile
13+
```
14+
15+
**Load specific profile with overrides:**
16+
```bash
17+
./gradlew -q execute -PmainClass=io.temporal.samples.envconfig.LoadProfile
18+
```
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# This is a sample configuration file for demonstrating Temporal's environment
2+
# configuration feature. It defines multiple profiles for different environments,
3+
# such as local development, production, and staging.
4+
5+
# Default profile for local development
6+
[profile.default]
7+
address = "localhost:7233"
8+
namespace = "default"
9+
10+
# Optional: Add custom gRPC headers
11+
[profile.default.grpc_meta]
12+
my-custom-header = "development-value"
13+
trace-id = "dev-trace-123"
14+
15+
# Staging profile with inline certificate data
16+
[profile.staging]
17+
address = "localhost:9999"
18+
namespace = "staging"
19+
20+
# An example production profile for Temporal Cloud
21+
[profile.prod]
22+
address = "your-namespace.a1b2c.tmprl.cloud:7233"
23+
namespace = "your-namespace"
24+
# Replace with your actual Temporal Cloud API key
25+
api_key = "your-api-key-here"
26+
27+
# TLS configuration for production
28+
[profile.prod.tls]
29+
# TLS is auto-enabled when an API key is present, but you can configure it
30+
# explicitly.
31+
# disabled = false
32+
33+
# Use certificate files for mTLS. Replace with actual paths.
34+
client_cert_path = "/etc/temporal/certs/client.pem"
35+
client_key_path = "/etc/temporal/certs/client.key"
36+
37+
# Custom headers for production
38+
[profile.prod.grpc_meta]
39+
environment = "production"
40+
service-version = "v1.2.3"

0 commit comments

Comments
 (0)