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:
Brian Strauch
2026-08-20 13:35:21 -07:00
committed by GitHub
parent 67f41f97d6
commit 3b191bd754
7 changed files with 72 additions and 33 deletions
+9 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
+9 -6
View File
@@ -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
View File
@@ -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)
+14 -4
View File
@@ -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)