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
5 changes: 5 additions & 0 deletions packages/aws-durable-execution-sdk-python-insight/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ and `top-level` vs `full-tree` operation detail all mirror the JS plugin.
Behavior is validated cross-SDK by the `insight` conformance suite
(`aws-durable-execution-conformance-tests-insight`).

> **Note (`on-change` emission).** In `on-change` mode, exporter calls currently
> run synchronously on the SDK checkpoint path, so a slow exporter can delay
> workflow progress. Asynchronous scheduling/coalescing is deferred and tracked
> in [issue #687](https://github.com/aws/aws-durable-execution-sdk-python/issues/687).

## Requirements

- `aws-durable-execution-sdk-python` with the plugin invocation hooks that
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

import datetime
import json
import math
import sys
import threading
from typing import Any, Callable
Expand Down Expand Up @@ -107,6 +108,13 @@ def _resolve_sampling_rate(rate: float | None) -> float:
return 1.0
if not isinstance(rate, (int, float)):
return 1.0
if isinstance(rate, float) and math.isnan(rate):
# Fail open. NaN compares False to everything, so without this guard it
# would flow through _should_sample (rate >= 1 -> False, rate <= 0 ->
# False, x < NaN -> False) and silently sample OUT every execution,
# disabling all instrumentation. Coerce to full sampling instead, which
# matches the JS plugin's treatment of non-finite/invalid rates.
return 1.0
if rate < 0 or rate > 1:
return max(0.0, min(1.0, float(rate)))
return float(rate)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
WorkflowInsightConfig,
workflow_insight,
)
from aws_durable_execution_sdk_python_insight.plugin import _resolve_sampling_rate

ARN = "arn:aws:lambda:us-west-2:123456789012:function:my-fn:$LATEST/durable-execution/exec-1/inv-1"
ARN_B = "arn:aws:lambda:us-west-2:123456789012:function:my-fn:$LATEST/durable-execution/exec-2/inv-1"
Expand Down Expand Up @@ -196,6 +197,22 @@ def test_sampling_zero_emits_nothing():
assert exporter.records == []


def test_resolve_sampling_rate_nan_fails_open_to_one():
# NaN compares False to everything; without the guard this would sample OUT
# every execution. It must fail open to full sampling (JS parity).
assert _resolve_sampling_rate(float("nan")) == 1.0


def test_nan_sampling_rate_emits_instead_of_silently_disabling():
exporter = CaptureExporter()
plugin = workflow_insight(
WorkflowInsightConfig(exporters=[exporter], sampling_rate=float("nan"))
)
_run(plugin, ops=[_step("greet")])
# A NaN rate must not disable instrumentation: the record is still emitted.
assert len(exporter.records) == 1


def test_content_omit_input_output_without_drop_flags():
exporter = CaptureExporter()
plugin = workflow_insight(
Expand Down
Loading