Files
tasks/common/nexus/failure_test.go
zeekay 40351cce6f rip: delete temporal fork — native ZAP-only tasksd
Goes from 135 MB binary with 1153 files importing go.temporal.io and 224
importing google.golang.org/grpc to a 10 MB native binary with ZERO of
either.

Deleted:
- tasks/, tasktests/, service/, chasm/, client/, api/, proto/, tools/
- cmd/tools/, components/, docker/
- schema/{cassandra,elasticsearch,mysql,postgresql,sqlite}/
- 40 tainted common/ subdirs + 7 top-level common files
- tests/testutils (no longer referenced after surviving deps drop common)

New cmd/tasksd (~100 lines) boots tasks.Embed (zap.Node) + http.Server.
New pkg/tasks/embed.go registers ZAP handlers for the SDK opcode surface
(0x0060-0x00A5). Workflow handlers return a 501 "not yet implemented"
envelope; native engine lands behind this contract.

Build:  go build ./cmd/tasksd → 10 MB
Vet:    go vet ./... → clean
Boot:   tasksd --zap-port 9999 --http :7243
Probes: /healthz, /v1/tasks/health → 200
UI:     /_/tasks/, / → 200 (embedded Vite bundle)
ZAP:    _tasks._tcp on :9999 (mDNS disabled; direct connect)

go.mod: tidy. No go.temporal.io. No google.golang.org/grpc.
2026-04-26 14:06:21 -07:00

326 lines
9.5 KiB
Go

package nexus
import (
"testing"
"github.com/nexus-rpc/sdk-go/nexus"
"github.com/stretchr/testify/require"
commonpb "go.temporal.io/api/common/v1"
enumspb "go.temporal.io/api/enums/v1"
failurepb "go.temporal.io/api/failure/v1"
"go.temporal.io/sdk/temporal"
"go.temporal.io/server/common/nexus/nexusrpc"
"go.temporal.io/server/common/testing/protorequire"
)
func TestRoundTrip_ApplicationFailure(t *testing.T) {
original := &failurepb.Failure{
Message: "application error",
StackTrace: "stack trace here",
EncodedAttributes: mustToPayload(t, "encoded"),
FailureInfo: &failurepb.Failure_ApplicationFailureInfo{
ApplicationFailureInfo: &failurepb.ApplicationFailureInfo{
Type: "CustomError",
NonRetryable: false,
Details: &commonpb.Payloads{
Payloads: []*commonpb.Payload{mustToPayload(t, "encoded")},
},
},
},
}
nexusFailure, err := TemporalFailureToNexusFailure(original)
require.NoError(t, err)
converted, err := NexusFailureToTemporalFailure(nexusFailure)
require.NoError(t, err)
protorequire.ProtoEqual(t, original, converted)
}
func TestRoundTrip_NexusHandlerFailure_Retryable(t *testing.T) {
original := &failurepb.Failure{
Message: "handler error - retryable",
StackTrace: "handler stack trace",
FailureInfo: &failurepb.Failure_NexusHandlerFailureInfo{
NexusHandlerFailureInfo: &failurepb.NexusHandlerFailureInfo{
Type: "CustomHandlerError",
RetryBehavior: enumspb.NEXUS_HANDLER_ERROR_RETRY_BEHAVIOR_RETRYABLE,
},
},
}
nexusFailure, err := TemporalFailureToNexusFailure(original)
require.NoError(t, err)
converted, err := NexusFailureToTemporalFailure(nexusFailure)
require.NoError(t, err)
protorequire.ProtoEqual(t, original, converted)
}
func TestRoundTrip_NexusHandlerFailure_NonRetryable(t *testing.T) {
original := &failurepb.Failure{
Message: "handler error - non-retryable",
StackTrace: "handler stack trace",
FailureInfo: &failurepb.Failure_NexusHandlerFailureInfo{
NexusHandlerFailureInfo: &failurepb.NexusHandlerFailureInfo{
Type: "FatalHandlerError",
RetryBehavior: enumspb.NEXUS_HANDLER_ERROR_RETRY_BEHAVIOR_NON_RETRYABLE,
},
},
}
nexusFailure, err := TemporalFailureToNexusFailure(original)
require.NoError(t, err)
converted, err := NexusFailureToTemporalFailure(nexusFailure)
require.NoError(t, err)
protorequire.ProtoEqual(t, original, converted)
}
func TestRoundTrip_NexusHandlerFailure_Unspecified(t *testing.T) {
original := &failurepb.Failure{
Message: "handler error - unspecified retry",
StackTrace: "handler stack trace",
FailureInfo: &failurepb.Failure_NexusHandlerFailureInfo{
NexusHandlerFailureInfo: &failurepb.NexusHandlerFailureInfo{
Type: "UnspecifiedHandlerError",
RetryBehavior: enumspb.NEXUS_HANDLER_ERROR_RETRY_BEHAVIOR_UNSPECIFIED,
},
},
}
nexusFailure, err := TemporalFailureToNexusFailure(original)
require.NoError(t, err)
converted, err := NexusFailureToTemporalFailure(nexusFailure)
require.NoError(t, err)
protorequire.ProtoEqual(t, original, converted)
}
func TestRoundTrip_NexusHandlerFailure_WithAttributes(t *testing.T) {
original := &failurepb.Failure{
Message: "handler error with attributes",
StackTrace: "handler stack trace",
FailureInfo: &failurepb.Failure_NexusHandlerFailureInfo{
NexusHandlerFailureInfo: &failurepb.NexusHandlerFailureInfo{
Type: "ComplexHandlerError",
RetryBehavior: enumspb.NEXUS_HANDLER_ERROR_RETRY_BEHAVIOR_RETRYABLE,
},
},
EncodedAttributes: mustToPayload(t, "encoded attributes"),
}
nexusFailure, err := TemporalFailureToNexusFailure(original)
require.NoError(t, err)
converted, err := NexusFailureToTemporalFailure(nexusFailure)
require.NoError(t, err)
protorequire.ProtoEqual(t, original, converted)
}
func TestRoundTrip_WithNestedCauses(t *testing.T) {
original := &failurepb.Failure{
Message: "top level failure",
StackTrace: "top stack trace",
FailureInfo: &failurepb.Failure_ApplicationFailureInfo{
ApplicationFailureInfo: &failurepb.ApplicationFailureInfo{
Type: "TopLevelError",
},
},
Cause: &failurepb.Failure{
Message: "middle failure",
StackTrace: "middle stack trace",
FailureInfo: &failurepb.Failure_TimeoutFailureInfo{
TimeoutFailureInfo: &failurepb.TimeoutFailureInfo{
TimeoutType: enumspb.TIMEOUT_TYPE_START_TO_CLOSE,
},
},
Cause: &failurepb.Failure{
Message: "root cause",
StackTrace: "root stack trace",
FailureInfo: &failurepb.Failure_ServerFailureInfo{
ServerFailureInfo: &failurepb.ServerFailureInfo{
NonRetryable: true,
},
},
},
},
}
nexusFailure, err := TemporalFailureToNexusFailure(original)
require.NoError(t, err)
converted, err := NexusFailureToTemporalFailure(nexusFailure)
require.NoError(t, err)
protorequire.ProtoEqual(t, original, converted)
}
func TestRoundTrip_EmptyFailure(t *testing.T) {
original := &failurepb.Failure{
Message: "simple message",
}
nexusFailure, err := TemporalFailureToNexusFailure(original)
require.NoError(t, err)
converted, err := NexusFailureToTemporalFailure(nexusFailure)
require.NoError(t, err)
protorequire.ProtoEqual(t, original, converted)
}
func TestRoundTrip_OnlyStackTrace(t *testing.T) {
original := &failurepb.Failure{
StackTrace: "just a stack trace",
}
nexusFailure, err := TemporalFailureToNexusFailure(original)
require.NoError(t, err)
converted, err := NexusFailureToTemporalFailure(nexusFailure)
require.NoError(t, err)
protorequire.ProtoEqual(t, original, converted)
}
func TestFromOperationFailedError(t *testing.T) {
nexusFailure, err := nexusrpc.DefaultFailureConverter().ErrorToFailure(&nexus.OperationError{
State: nexus.OperationStateFailed,
Message: "operation failed",
StackTrace: "stack trace",
})
require.NoError(t, err)
cause, err := TemporalFailureToNexusFailure(
temporal.GetDefaultFailureConverter().ErrorToFailure(
temporal.NewApplicationError("app err", "CustomError", "details"),
),
)
require.NoError(t, err)
nexusFailure.Cause = &cause
converted, err := NexusFailureToTemporalFailure(nexusFailure)
require.NoError(t, err)
expected := &failurepb.Failure{
Message: "operation failed",
StackTrace: "stack trace",
FailureInfo: &failurepb.Failure_ApplicationFailureInfo{
ApplicationFailureInfo: &failurepb.ApplicationFailureInfo{
NonRetryable: true,
Type: "OperationError",
},
},
Cause: &failurepb.Failure{
Message: "app err",
Source: "GoSDK",
FailureInfo: &failurepb.Failure_ApplicationFailureInfo{
ApplicationFailureInfo: &failurepb.ApplicationFailureInfo{
Type: "CustomError",
Details: &commonpb.Payloads{
Payloads: []*commonpb.Payload{mustToPayload(t, "details")},
},
},
},
},
}
protorequire.ProtoEqual(t, expected, converted)
}
func TestNexusFailureToTemporalFailure_UnknownMetadataType(t *testing.T) {
nf := nexus.Failure{
Message: "unknown failure",
StackTrace: "unknown stack trace",
Metadata: map[string]string{
"type": "some.custom.Type",
},
Details: []byte(`{"key":"value"}`),
}
converted, err := NexusFailureToTemporalFailure(nf)
require.NoError(t, err)
require.Equal(t, "unknown failure", converted.GetMessage())
require.Equal(t, "unknown stack trace", converted.GetStackTrace())
appInfo := converted.GetApplicationFailureInfo()
require.NotNil(t, appInfo)
require.Equal(t, "NexusFailure", appInfo.GetType())
require.NotNil(t, appInfo.GetDetails())
require.Len(t, appInfo.GetDetails().GetPayloads(), 1)
}
func TestNexusFailureToTemporalFailure_NoMetadataWithDetails(t *testing.T) {
nf := nexus.Failure{
Message: "bare failure",
Details: []byte(`{"info":"data"}`),
}
converted, err := NexusFailureToTemporalFailure(nf)
require.NoError(t, err)
require.Equal(t, "bare failure", converted.GetMessage())
appInfo := converted.GetApplicationFailureInfo()
require.NotNil(t, appInfo)
require.Equal(t, "NexusFailure", appInfo.GetType())
require.NotNil(t, appInfo.GetDetails())
require.Len(t, appInfo.GetDetails().GetPayloads(), 1)
}
func TestNexusFailureToTemporalFailure_NoMetadataNoDetails(t *testing.T) {
nf := nexus.Failure{
Message: "plain failure",
}
converted, err := NexusFailureToTemporalFailure(nf)
require.NoError(t, err)
require.Equal(t, "plain failure", converted.GetMessage())
require.Nil(t, converted.GetFailureInfo())
}
func TestFromOperationCanceledError(t *testing.T) {
nexusFailure, err := nexusrpc.DefaultFailureConverter().ErrorToFailure(&nexus.OperationError{
State: nexus.OperationStateCanceled,
Message: "operation canceled",
StackTrace: "stack trace",
})
require.NoError(t, err)
cause, err := TemporalFailureToNexusFailure(
temporal.GetDefaultFailureConverter().ErrorToFailure(
temporal.NewApplicationError("app err", "CustomError", "details"),
),
)
require.NoError(t, err)
nexusFailure.Cause = &cause
converted, err := NexusFailureToTemporalFailure(nexusFailure)
require.NoError(t, err)
expected := &failurepb.Failure{
Message: "operation canceled",
StackTrace: "stack trace",
FailureInfo: &failurepb.Failure_CanceledFailureInfo{
CanceledFailureInfo: &failurepb.CanceledFailureInfo{},
},
Cause: &failurepb.Failure{
Message: "app err",
Source: "GoSDK",
FailureInfo: &failurepb.Failure_ApplicationFailureInfo{
ApplicationFailureInfo: &failurepb.ApplicationFailureInfo{
Type: "CustomError",
Details: &commonpb.Payloads{
Payloads: []*commonpb.Payload{mustToPayload(t, "details")},
},
},
},
},
}
protorequire.ProtoEqual(t, expected, converted)
}