mirror of
https://github.com/temporalio/skill-temporal-developer.git
synced 2026-09-14 13:52:58 +08:00
Use env-config for quick-start connections (#261)
* Use env-config for quick-start connections * Pass namespace from env-config to TypeScript Workers NativeConnection carries no namespace, and WorkerOptions defaults to 'default' when it is omitted. With TEMPORAL_NAMESPACE (or a temporal.toml profile) set, the Worker polled 'default' while the Client used the configured namespace, so the workflow was never picked up. Verified against a dev server with a non-default namespace: the previous snippets left the workflow Running with pollers on 'default'; with namespace: config.namespace both quick starts complete. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -55,9 +55,12 @@ public class GreetingWorkflow
|
||||
|
||||
```csharp
|
||||
using Temporalio.Client;
|
||||
using Temporalio.Common.EnvConfig;
|
||||
using Temporalio.Worker;
|
||||
|
||||
var client = await TemporalClient.ConnectAsync(new("localhost:7233"));
|
||||
var connectOptions = ClientEnvConfig.LoadClientConnectOptions();
|
||||
connectOptions.TargetHost ??= "localhost:7233";
|
||||
var client = await TemporalClient.ConnectAsync(connectOptions);
|
||||
|
||||
using var tokenSource = new CancellationTokenSource();
|
||||
Console.CancelKeyPress += (_, eventArgs) =>
|
||||
@@ -83,8 +86,11 @@ await worker.ExecuteAsync(tokenSource.Token);
|
||||
|
||||
```csharp
|
||||
using Temporalio.Client;
|
||||
using Temporalio.Common.EnvConfig;
|
||||
|
||||
var client = await TemporalClient.ConnectAsync(new("localhost:7233"));
|
||||
var connectOptions = ClientEnvConfig.LoadClientConnectOptions();
|
||||
connectOptions.TargetHost ??= "localhost:7233";
|
||||
var client = await TemporalClient.ConnectAsync(connectOptions);
|
||||
|
||||
var result = await client.ExecuteWorkflowAsync(
|
||||
(GreetingWorkflow wf) => wf.RunAsync("my name"),
|
||||
@@ -114,7 +120,7 @@ Console.WriteLine($"Result: {result}");
|
||||
|
||||
### Worker Setup
|
||||
|
||||
- Connect client, create `TemporalWorker` with workflows and activities
|
||||
- Load connection settings with `ClientEnvConfig.LoadClientConnectOptions()`, connect the client, and create `TemporalWorker` with workflows and activities
|
||||
- Use `AddWorkflow<T>()` and `AddAllActivities(instance)` or `AddActivity(method)`
|
||||
|
||||
### Determinism
|
||||
|
||||
+6
-4
@@ -9,7 +9,7 @@ The Temporal Go SDK (`go.temporal.io/sdk`) provides a strongly-typed, idiomatic
|
||||
**Add Dependency:** In your Go module, add the Temporal SDK:
|
||||
|
||||
```bash
|
||||
go get go.temporal.io/sdk
|
||||
go get go.temporal.io/sdk go.temporal.io/sdk/contrib/envconfig
|
||||
```
|
||||
|
||||
**workflows/greeting.go** - Workflow definition:
|
||||
@@ -67,11 +67,12 @@ import (
|
||||
"yourmodule/workflows"
|
||||
|
||||
"go.temporal.io/sdk/client"
|
||||
"go.temporal.io/sdk/contrib/envconfig"
|
||||
"go.temporal.io/sdk/worker"
|
||||
)
|
||||
|
||||
func main() {
|
||||
c, err := client.Dial(client.Options{})
|
||||
c, err := client.Dial(envconfig.MustLoadDefaultClientOptions())
|
||||
if err != nil {
|
||||
log.Fatalln("Unable to create client", err)
|
||||
}
|
||||
@@ -107,10 +108,11 @@ import (
|
||||
|
||||
"github.com/google/uuid"
|
||||
"go.temporal.io/sdk/client"
|
||||
"go.temporal.io/sdk/contrib/envconfig"
|
||||
)
|
||||
|
||||
func main() {
|
||||
c, err := client.Dial(client.Options{})
|
||||
c, err := client.Dial(envconfig.MustLoadDefaultClientOptions())
|
||||
if err != nil {
|
||||
log.Fatalln("Unable to create client", err)
|
||||
}
|
||||
@@ -157,7 +159,7 @@ func main() {
|
||||
|
||||
### Worker Setup
|
||||
|
||||
- Create client with `client.Dial(client.Options{})`
|
||||
- Load file- and environment-based connection settings with `envconfig.MustLoadDefaultClientOptions()`, then pass them to `client.Dial`
|
||||
- Create worker with `worker.New(c, "task-queue", worker.Options{})`
|
||||
- Register workflows and activities
|
||||
- Run with `w.Run(worker.InterruptCh())`
|
||||
|
||||
+21
-9
@@ -12,6 +12,7 @@ Gradle:
|
||||
|
||||
```groovy
|
||||
implementation 'io.temporal:temporal-sdk:1.+'
|
||||
implementation 'io.temporal:temporal-envconfig:1.+'
|
||||
```
|
||||
|
||||
Maven:
|
||||
@@ -22,6 +23,11 @@ Maven:
|
||||
<artifactId>temporal-sdk</artifactId>
|
||||
<version>[1.0,)</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.temporal</groupId>
|
||||
<artifactId>temporal-envconfig</artifactId>
|
||||
<version>[1.0,)</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
**GreetActivities.java** - Activity interface:
|
||||
@@ -102,18 +108,19 @@ public class GreetingWorkflowImpl implements GreetingWorkflow {
|
||||
package greetingapp;
|
||||
|
||||
import io.temporal.client.WorkflowClient;
|
||||
import io.temporal.envconfig.ClientConfigProfile;
|
||||
import io.temporal.serviceclient.WorkflowServiceStubs;
|
||||
import io.temporal.worker.Worker;
|
||||
import io.temporal.worker.WorkerFactory;
|
||||
|
||||
public class GreetingWorker {
|
||||
|
||||
public static void main(String[] args) {
|
||||
// Create gRPC stubs for local dev server (localhost:7233)
|
||||
WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
|
||||
|
||||
// Create client
|
||||
WorkflowClient client = WorkflowClient.newInstance(service);
|
||||
public static void main(String[] args) throws Exception {
|
||||
ClientConfigProfile profile = ClientConfigProfile.load();
|
||||
WorkflowServiceStubs service =
|
||||
WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
|
||||
WorkflowClient client =
|
||||
WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
|
||||
|
||||
// Create factory and worker
|
||||
WorkerFactory factory = WorkerFactory.newInstance(client);
|
||||
@@ -140,15 +147,19 @@ package greetingapp;
|
||||
|
||||
import io.temporal.client.WorkflowClient;
|
||||
import io.temporal.client.WorkflowOptions;
|
||||
import io.temporal.envconfig.ClientConfigProfile;
|
||||
import io.temporal.serviceclient.WorkflowServiceStubs;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class Starter {
|
||||
|
||||
public static void main(String[] args) {
|
||||
WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
|
||||
WorkflowClient client = WorkflowClient.newInstance(service);
|
||||
public static void main(String[] args) throws Exception {
|
||||
ClientConfigProfile profile = ClientConfigProfile.load();
|
||||
WorkflowServiceStubs service =
|
||||
WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());
|
||||
WorkflowClient client =
|
||||
WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());
|
||||
|
||||
GreetingWorkflow workflow = client.newWorkflowStub(
|
||||
GreetingWorkflow.class,
|
||||
@@ -187,6 +198,7 @@ public class Starter {
|
||||
|
||||
### Worker Setup
|
||||
|
||||
- Load connection settings with `ClientConfigProfile.load()` and use the profile to configure both service stubs and the client
|
||||
- `WorkflowServiceStubs` -- gRPC connection to Temporal Server
|
||||
- `WorkflowClient` -- client used by worker to communicate with server
|
||||
- `WorkerFactory` -- creates Worker instances
|
||||
|
||||
@@ -42,6 +42,7 @@ class GreetingWorkflow:
|
||||
import asyncio
|
||||
import concurrent.futures
|
||||
from temporalio.client import Client
|
||||
from temporalio.envconfig import ClientConfig
|
||||
from temporalio.worker import Worker
|
||||
|
||||
# Import the activity and workflow from our other files
|
||||
@@ -49,9 +50,9 @@ from activities.greet import greet
|
||||
from workflows.greeting import GreetingWorkflow
|
||||
|
||||
async def main():
|
||||
# Create client connected to server at the given address
|
||||
# This is the default port for `temporal server start-dev`
|
||||
client = await Client.connect("localhost:7233")
|
||||
connect_config = ClientConfig.load_client_connect_config()
|
||||
connect_config.setdefault("target_host", "localhost:7233")
|
||||
client = await Client.connect(**connect_config)
|
||||
|
||||
# Run the worker
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=100) as activity_executor:
|
||||
@@ -77,14 +78,16 @@ if __name__ == "__main__":
|
||||
```python
|
||||
import asyncio
|
||||
from temporalio.client import Client
|
||||
from temporalio.envconfig import ClientConfig
|
||||
import uuid
|
||||
|
||||
# Import the workflow from the previous code
|
||||
from workflows.greeting import GreetingWorkflow
|
||||
|
||||
async def main():
|
||||
# Create client connected to server at the given address
|
||||
client = await Client.connect("localhost:7233")
|
||||
connect_config = ClientConfig.load_client_connect_config()
|
||||
connect_config.setdefault("target_host", "localhost:7233")
|
||||
client = await Client.connect(**connect_config)
|
||||
|
||||
# Execute a workflow
|
||||
result = await client.execute_workflow(GreetingWorkflow.run, "my name", id=str(uuid.uuid4()), task_queue="my-task-queue")
|
||||
@@ -119,7 +122,7 @@ See `sync-vs-async.md` for detailed guidance on choosing between sync and async.
|
||||
|
||||
### Worker Setup
|
||||
|
||||
- Connect client, create Worker with workflows and activities
|
||||
- Load connection settings with `ClientConfig.load_client_connect_config()`, connect the client, and create a Worker with workflows and activities
|
||||
- Run the worker
|
||||
- Activities can specify custom executor
|
||||
|
||||
|
||||
+11
-6
@@ -37,13 +37,15 @@ end
|
||||
**worker.rb** - Worker setup (imports activity and workflow, runs indefinitely and processes tasks):
|
||||
```ruby
|
||||
require 'temporalio/client'
|
||||
require 'temporalio/env_config'
|
||||
require 'temporalio/worker'
|
||||
require_relative 'say_hello_activity'
|
||||
require_relative 'say_hello_workflow'
|
||||
|
||||
# Create client connected to server at the given address
|
||||
# This is the default port for `temporal server start-dev`
|
||||
client = Temporalio::Client.connect('localhost:7233', 'default')
|
||||
args, kwargs = Temporalio::EnvConfig::ClientConfig.load_client_connect_options
|
||||
args[0] ||= 'localhost:7233'
|
||||
args[1] ||= 'default'
|
||||
client = Temporalio::Client.connect(*args, **kwargs)
|
||||
|
||||
# Create and run the worker
|
||||
worker = Temporalio::Worker.new(
|
||||
@@ -62,11 +64,14 @@ worker.run
|
||||
**execute_workflow.rb** - Start a workflow execution:
|
||||
```ruby
|
||||
require 'temporalio/client'
|
||||
require 'temporalio/env_config'
|
||||
require 'securerandom'
|
||||
require_relative 'say_hello_workflow'
|
||||
|
||||
# Create client connected to server at the given address
|
||||
client = Temporalio::Client.connect('localhost:7233', 'default')
|
||||
args, kwargs = Temporalio::EnvConfig::ClientConfig.load_client_connect_options
|
||||
args[0] ||= 'localhost:7233'
|
||||
args[1] ||= 'default'
|
||||
client = Temporalio::Client.connect(*args, **kwargs)
|
||||
|
||||
# Execute a workflow
|
||||
result = client.execute_workflow(
|
||||
@@ -96,7 +101,7 @@ puts "Result: #{result}"
|
||||
- Can access `Temporalio::Activity::Context.current` for heartbeating
|
||||
|
||||
### Worker Setup
|
||||
- Connect client with `Temporalio::Client.connect`
|
||||
- Load connection settings with `Temporalio::EnvConfig::ClientConfig.load_client_connect_options` and connect with `Temporalio::Client.connect`
|
||||
- Create worker with `Temporalio::Worker.new(client:, task_queue:, workflows:, activities:)`
|
||||
- Run with `worker.run`
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ async function run() {
|
||||
const connection = await NativeConnection.connect(config.connectionOptions);
|
||||
const worker = await Worker.create({
|
||||
connection,
|
||||
namespace: config.namespace,
|
||||
taskQueue: 'hello-standalone-activities',
|
||||
activities, // register whatever your activity(ies) is/are
|
||||
});
|
||||
@@ -55,7 +56,7 @@ import { loadClientConnectConfig } from '@temporalio/envconfig';
|
||||
|
||||
const config = loadClientConnectConfig();
|
||||
const connection = await Connection.connect(config.connectionOptions);
|
||||
const client = new Client({ connection });
|
||||
const client = new Client({ connection, namespace: config.namespace });
|
||||
```
|
||||
|
||||
### Execute (wait for result)
|
||||
|
||||
@@ -15,7 +15,7 @@ Temporal workflows are durable through history replay. For details on how this w
|
||||
**Add Dependencies:** Install the Temporal SDK packages (use the package manager appropriate for your project):
|
||||
|
||||
```bash
|
||||
npm install @temporalio/client @temporalio/worker @temporalio/workflow @temporalio/activity
|
||||
npm install @temporalio/client @temporalio/worker @temporalio/workflow @temporalio/activity @temporalio/envconfig
|
||||
```
|
||||
|
||||
Note: if you are working in production, it is strongly advised to use ~ version constraints, i.e. `npm install ... --save-prefix='~'` if using NPM.
|
||||
@@ -46,11 +46,16 @@ export async function greetingWorkflow(name: string): Promise<string> {
|
||||
**worker.ts** - Worker setup (registers activity and workflow, runs indefinitely and processes tasks):
|
||||
|
||||
```typescript
|
||||
import { Worker } from '@temporalio/worker';
|
||||
import { NativeConnection, Worker } from '@temporalio/worker';
|
||||
import { loadClientConnectConfig } from '@temporalio/envconfig';
|
||||
import * as activities from './activities';
|
||||
|
||||
async function run() {
|
||||
const config = loadClientConnectConfig();
|
||||
const connection = await NativeConnection.connect(config.connectionOptions);
|
||||
const worker = await Worker.create({
|
||||
connection,
|
||||
namespace: config.namespace,
|
||||
workflowsPath: require.resolve('./workflows'), // For production, use workflowBundle instead
|
||||
activities,
|
||||
taskQueue: 'greeting-queue',
|
||||
@@ -68,12 +73,15 @@ run().catch(console.error);
|
||||
**client.ts** - Start a workflow execution:
|
||||
|
||||
```typescript
|
||||
import { Client } from '@temporalio/client';
|
||||
import { Client, Connection } from '@temporalio/client';
|
||||
import { loadClientConnectConfig } from '@temporalio/envconfig';
|
||||
import { greetingWorkflow } from './workflows';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
async function run() {
|
||||
const client = new Client();
|
||||
const config = loadClientConnectConfig();
|
||||
const connection = await Connection.connect(config.connectionOptions);
|
||||
const client = new Client({ connection, namespace: config.namespace });
|
||||
|
||||
const result = await client.workflow.execute(greetingWorkflow, {
|
||||
workflowId: uuid(),
|
||||
@@ -105,6 +113,8 @@ run().catch(console.error);
|
||||
|
||||
### Worker Setup
|
||||
|
||||
- Load connection settings with `loadClientConnectConfig()` and pass them to `NativeConnection.connect()`
|
||||
- Pass `namespace: config.namespace` to `Worker.create()` - `NativeConnection` carries no namespace, and the Worker defaults to `default` without it
|
||||
- Use `Worker.create()` with `workflowsPath` (dev) or `workflowBundle` (production) - see `references/typescript/gotchas.md`
|
||||
- Import activities directly (not via proxy)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user