Files
tasks/service/history/worker_versioning_util.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

238 lines
8.3 KiB
Go

package history
import (
"context"
enumspb "go.temporal.io/api/enums/v1"
"go.temporal.io/api/serviceerror"
persistencespb "go.temporal.io/server/api/persistence/v1"
taskqueuespb "go.temporal.io/server/api/taskqueue/v1"
"go.temporal.io/server/common"
"go.temporal.io/server/common/log"
"go.temporal.io/server/common/log/tag"
"go.temporal.io/server/common/metrics"
"go.temporal.io/server/common/persistence"
"go.temporal.io/server/common/worker_versioning"
"go.temporal.io/server/service/history/consts"
historyi "go.temporal.io/server/service/history/interfaces"
"go.temporal.io/server/service/history/tasks"
"go.temporal.io/server/service/history/workflow/cache"
)
func updateIndependentActivityBuildId(
ctx context.Context,
task tasks.Task,
buildId string,
shardContext historyi.ShardContext,
transactionPolicy historyi.TransactionPolicy,
workflowCache cache.Cache,
metricsHandler metrics.Handler,
logger log.Logger,
) (retErr error) {
if buildId == "" {
// the task is sync-matched, or versioning is not enabled for this Task Queue
return nil
}
defer func() {
if retErr != nil {
// An independent task is scheduled but we could not persist the assigned build ID in mutable state.
// This is only an issue for user visibility: until the task is started user would not see the assigned
// build ID.
// Since it does not affect WF progress, just logging warn and skipping the error.
// TODO: let the error bubble up so the task is rescheduled and build ID is fully updated
logger.Warn("failed to update activity's assigned build ID", append(tasks.Tags(task), tag.Error(retErr))...)
}
retErr = nil
}()
// We should reach to this point only when all the following conditions are true:
// - assignment rules are added for the Task Queue (i.e. worker versioning is enabled)
// - sync-match did not happen for this task
// - the activity is on a different task queue (or otherwise asked to be independently assigned to a build ID)
weContext, release, err := getWorkflowExecutionContextForTask(ctx, shardContext, workflowCache, task)
if err != nil {
return err
}
defer func() {
release(retErr)
}()
var mutableState historyi.MutableState
var scheduledEventId int64
var taskVersion int64
switch t := task.(type) {
case *tasks.ActivityTask:
scheduledEventId = t.ScheduledEventID
taskVersion = t.Version
mutableState, err = loadMutableStateForTransferTask(ctx, shardContext, weContext, t, metricsHandler, logger)
case *tasks.ActivityRetryTimerTask:
scheduledEventId = t.EventID
taskVersion = t.Version
mutableState, err = loadMutableStateForTimerTask(ctx, shardContext, weContext, t, metricsHandler, logger)
default:
return serviceerror.NewInvalidArgument("task type not supported")
}
if err != nil {
return err
}
if mutableState == nil {
return consts.ErrWorkflowExecutionNotFound
}
ai, activityRunning := mutableState.GetActivityInfo(scheduledEventId)
if !activityRunning {
// We did not find the activity task, it means that it's already completed.
return nil
}
err = CheckTaskVersion(shardContext, logger, mutableState.GetNamespaceEntry(), ai.Version, taskVersion, task)
if err != nil {
return err
}
err = mutableState.UpdateActivity(ai.ScheduledEventId, func(activityInfo *persistencespb.ActivityInfo, _ historyi.MutableState) error {
activityInfo.BuildIdInfo = &persistencespb.ActivityInfo_LastIndependentlyAssignedBuildId{LastIndependentlyAssignedBuildId: buildId}
return nil
})
if err != nil {
return err
}
return weContext.UpdateWorkflowExecutionWithNew(
ctx,
shardContext,
persistence.UpdateWorkflowModeUpdateCurrent,
nil,
nil,
transactionPolicy,
nil,
)
}
// initializeWorkflowAssignedBuildId sets the wf assigned build ID after scheduling the first workflow task, based on
// the build ID returned by matching.
func initializeWorkflowAssignedBuildId(
ctx context.Context,
transferTask *tasks.WorkflowTask,
buildId string,
shardContext historyi.ShardContext,
transactionPolicy historyi.TransactionPolicy,
workflowCache cache.Cache,
metricsHandler metrics.Handler,
logger log.Logger,
) (retErr error) {
if buildId == "" {
// the task is sync-matched, or versioning is not enabled for this Task Queue
return nil
}
defer func() {
if retErr != nil {
// The first workflow task is scheduled but we could not persist the assigned build ID in mutable state.
// This is only an issue for user visibility: until the task is started user would not see the assigned
// build ID.
// Since it does not affect WF progress, just logging warn and skipping the error.
// TODO: let the error bubble up so the task is rescheduled and build ID is fully updated
logger.Error("failed to update workflow's assigned build ID", append(tasks.Tags(transferTask), tag.Error(retErr))...)
}
retErr = nil
}()
// We should reach to this point only when all the following conditions are true:
// - assignment rules are added for the Task Queue (i.e. worker versioning is enabled)
// - sync-match did not happen for this task
// - this is the first workflow task of the execution
// - the workflow has not inherited a build ID (for child WF or CaN)
weContext, release, err := getWorkflowExecutionContextForTask(ctx, shardContext, workflowCache, transferTask)
if err != nil {
return err
}
mutableState, err := loadMutableStateForTransferTask(ctx, shardContext, weContext, transferTask, metricsHandler, logger)
if err != nil {
release(err)
return err
}
defer func() {
release(retErr)
}()
if mutableState == nil {
return consts.ErrWorkflowExecutionNotFound
}
workflowTask := mutableState.GetWorkflowTaskByID(transferTask.ScheduledEventID)
if workflowTask == nil {
return nil
}
err = CheckTaskVersion(shardContext, logger, mutableState.GetNamespaceEntry(), workflowTask.Version, transferTask.Version, transferTask)
if err != nil {
return err
}
if mutableState.HasCompletedAnyWorkflowTask() || workflowTask.StartedEventID != common.EmptyEventID {
// workflow task is running or already completed. buildId is potentially stale and useless.
// workflow's assigned build ID should be already updated via RecordWorkflowTaskStarted
return nil
}
err = mutableState.UpdateBuildIdAssignment(buildId)
if err != nil {
return err
}
return weContext.UpdateWorkflowExecutionWithNew(
ctx,
shardContext,
persistence.UpdateWorkflowModeUpdateCurrent,
nil,
nil,
transactionPolicy,
nil,
)
}
func MakeDirectiveForWorkflowTask(ms historyi.MutableState) *taskqueuespb.TaskVersionDirective {
return worker_versioning.MakeDirectiveForWorkflowTask(
ms.GetInheritedBuildId(),
ms.GetAssignedBuildId(),
ms.GetMostRecentWorkerVersionStamp(),
ms.HasCompletedAnyWorkflowTask(),
ms.GetEffectiveVersioningBehavior(),
ms.GetEffectiveDeployment(),
ms.GetVersioningRevisionNumber(),
ms.GetShouldUseRampingVersion(),
)
}
func MakeDirectiveForActivityTask(mutableState historyi.MutableState, activityInfo *persistencespb.ActivityInfo) *taskqueuespb.TaskVersionDirective {
if behavior := mutableState.GetEffectiveVersioningBehavior(); behavior != enumspb.VERSIONING_BEHAVIOR_UNSPECIFIED {
d := mutableState.GetEffectiveDeployment()
return &taskqueuespb.TaskVersionDirective{Behavior: behavior,
DeploymentVersion: worker_versioning.DeploymentVersionFromDeployment(d),
RevisionNumber: mutableState.GetVersioningRevisionNumber(),
// Don't pass UseRampingVersion for activity tasks, because it only applies to
// the first workflow task of a CaN run. Activities are always scheduled by a WFT completion,
// so by the time an activity task is dispatched the first WFT has already completed and
// GetShouldUseRampingVersion() would return false anyway. Passing nil explicitly to make it very
// explicit that UseRampingVersion is not used for activities.
UseRampingVersion: false,
}
}
if !activityInfo.UseCompatibleVersion && activityInfo.GetUseWorkflowBuildIdInfo() == nil {
return worker_versioning.MakeUseAssignmentRulesDirective()
} else if id := mutableState.GetAssignedBuildId(); id != "" {
return worker_versioning.MakeBuildIdDirective(id)
} else if id := worker_versioning.BuildIdIfUsingVersioning(mutableState.GetMostRecentWorkerVersionStamp()); id != "" {
// TODO: old versioning only [cleanup-old-wv]
return worker_versioning.MakeBuildIdDirective(id)
}
// else: unversioned execution
return nil
}