- [Improvement] Refreshed dependencies. Direct:
temporalio1.62.7 → 1.62.13,castore1.0.18 → 1.0.21,jason1.4.4 → 1.4.5, plus the dev/test tools (mox1.2.0 → 1.3.1,ex_doc0.40.1 → 0.40.4,credo1.7.17 → 1.7.19,dialyxir1.4.7 → 1.4.8). Transitively this pulls the transport forward:gun2.2.0 → 2.6.0,cowlib2.16.0 → 2.20.0,cowboy2.14.2 → 2.19.0 (clearing CVE-2026-43966, the HTTP request/response splitting issue fixed in cowboy 2.16.0),mint1.7.1 → 1.10.0,ranch2.2.0 → 2.3.0,protobuf0.16.0 → 0.16.1,telemetry1.4.1 → 1.4.2. No API or behavior change; the reconnect and GOAWAY-retry paths added in 0.2.2/0.2.4 still match on the samegunerror strings under 2.6.0. - [Note]
grpcstays on 0.11.5 and still carries four open advisories (CVE-2026-48853 CRITICAL, CVE-2026-48599 / CVE-2026-53430 / CVE-2026-48854 HIGH). All four are fixed ingrpc1.0.0, which we cannot take yet:temporalio1.62.13 itself requiresgrpc ~> 0.11.0. None of the four is reachable from this client — the RCE needsGRPC.Codec.Erlpackregistered as a server codec, the authorization bypass needs HTTP transcoding, and the two exhaustion bugs are server request-body paths. This library is client-only and registers no custom codec, so the exposure is packaging, not runtime. Tracked separately for whentemporaliounblocks the 1.0 line.
- [New Feature]
TemporalEx.describe_task_queue/2,3— callsWorkflowService/DescribeTaskQueueand decodes it to a plain map:%{pollers: [%{identity, last_access_time, rate_per_second}], stats: %{backlog_count, backlog_age_ms, tasks_add_rate, tasks_dispatch_rate} | nil}. A worker polls per task type, so the queue is described per type —:workflow(default),:activity, or:nexus;report_statsdefaults on, andbacklog_age_msstaysnilwhen unreported so an unknown age never reads as a real 0. An emptypollerslist is the direct answer to "nothing is listening on this queue".TemporalEx.Converter.TaskQueueholds the request builder and response decoder.
- [Fix]
TemporalEx.Client.Connectiontemp PEM files now use a strongly-random name (:crypto.strong_rand_bytes/1) instead of<os_pid>-<System.unique_integer/1>. The 0.2.1 scheme is deterministic across BEAM restarts — a containerized BEAM keeps a stable OS pid andunique_integerresets from a low value on each boot — so a boot that wrote PEM files and crashed before cleanup (cleanup only runs on graceful shutdown) left names the next boot regenerated exactly. With a persisted/tmp(an emptyDir survives container restarts) every candidate then collides on:eexistand the client raisescould not allocate a unique temp PEM path after 8 attempts, failingTemporalEx.Client.initand crash-looping the host application permanently. Random names are independent of pid, counter, and restart, so they never collide with leftover residue; the 8-attempt retry stays as defense-in-depth. Supersedes the 0.2.1 pid-suffix mitigation and covers both the multi-BEAM and the restart cases.
- [Fix]
TemporalEx.Clientnow reconnects and retries once when an RPC is refused by a connection the peer is draining — gun's:stream_error: :closing(the HTTP/2 GOAWAY akeepAliveMaxConnectionAgerecycle sends) or a{:goaway, …}abovelast_stream_id. Both guarantee the server never processed the stream, so the retry can't double-execute; previously the recycle leaked to callers ascode: 13. A server-sent RST (:cancel) or mid-flight:closedis left to surface, since the server may have processed the request first.
- [Improvement]
namespace/1anddata_converter/1are served from:persistent_terminstead of aGenServer.call. These immutable reads are now lock-free and no longer share the client mailbox, so a concurrent caller blocked mid-connectcan't make them time out. Removes the{:timeout, {GenServer, :call, [_, :get_namespace, 5000]}}bursts seen on every facade op (describe/start/signal) during a Temporal blip.
- [Fix]
TemporalEx.Clientno longer sticks on a dead gRPC channel after mid-RPC gun death (:down: :normal/:down: :noproc/ connection errors): the channel is dropped and the samerpc/4reconnects and retries once, so a single transport blip is usually invisible to callers. - [Improvement] RPC network I/O runs in the caller process, not inside the GenServer. Concurrent RPCs multiplex over one HTTP/2 connection; cheap
namespace/1/data_converter/1reads no longer queue behind a long Temporal call.
- [Fix]
TemporalEx.Client.Connection.write_temp_pem_file!/2no longer crashes withMatchError {:error, :eexist}when two BEAMs on the same host both initialize a Temporal client. The temp filename now includes:os.getpid()so independent BEAMs don't share theSystem.unique_integer/1suffix space, and the allocator retries on collision up to 8 attempts before raising. Non-:eexisterrors now surface a real message instead of aMatchError. Surfaced while iterating on pipex's cluster harness, which boots three sibling BEAMs alongside the test process.
- [New Feature] Added
TemporalEx.create_schedule/3for creating Temporal Schedules, returning aTemporalEx.ScheduleHandle. Supports interval, calendar, and cron specs; overlap / catchup / pause-on-failure policies; initial paused state; memos and search attributes. - [New Feature] Added
TemporalEx.ScheduleHandlestruct for referencing an existing schedule. - [New Feature] Added
TemporalEx.Converter.Scheduleto encode schedule options into the Temporal RPC request. - [New Feature] Added schedule-related error variants to
TemporalEx.Error. - [Improvement]
TemporalEx.Error.from_rpc_error/2now classifiesALREADY_EXISTS/NOT_FOUNDstatus codes using structured gRPC error details (WorkflowExecutionAlreadyStartedFailure,NamespaceNotFoundFailure,QueryFailedFailure) plus a caller-supplied:contextoption (:workflow/:schedule) rather than substring-matching the error message. Previously a workflow whose id contained the word "schedule" (e.g.daily-schedule-sync) could be misclassified as a schedule error, breaking caller pattern matches. - [Improvement] Refreshed dependencies.
- [Improvement] Expanded README with schedule usage examples.
- [New Feature] Initial release of the Temporal client SDK for Elixir.
- [New Feature]
TemporalEx.ClientGenServer managing the gRPC connection and data converter. - [New Feature] Workflow lifecycle API:
start_workflow/4,TemporalEx.WorkflowHandle.signal/4,TemporalEx.WorkflowHandle.terminate/2,TemporalEx.WorkflowHandle.result/1. - [New Feature] Workflow history retrieval via
TemporalEx.get_workflow_execution_history/3. - [New Feature] Payload / data converter layer (
TemporalEx.Converter.Payload,TemporalEx.Converter.Common) with protobuf construction hidden from callers. - [Fix] Ensured the workflow service stub module is loaded before checking exports.