mirror of
https://github.com/hanzoai/tasks.git
synced 2026-10-04 02:04:03 +00:00
### Overview * The aim is to "reapply" updates after workflow reset and during history replication conflict resolution. This is analogous to what we do already for signals. * We do this by making a pass through the candidate events and selecting `UpdateAccepted` events. We convert these into a new event type `UpdateRequested` and apply that to the new history branch (we cannot treat the update as accepted; we want it to be submitted to the validator on the new branch) * But we must also handle the `UpdateRequested` events themselves during reapply, in the case where an execution is subject to multiple resets / replication conflicts. * The `UpdateRequested` event always contains the original request payload. * These changes require us to modify some of our logic: until now, we had been using the `UpdateAccepted` event to store the request payload (needed by SDKs for replay). But in this PR, an `UpdateAccepted` is written without request payload when preceded by an `UpdateRequested`, and it is the `UpdateRequested` event that the SDKs will use during replay in that situation. SDKs must handle the new event sequences that are possible; an old SDK will not work correctly with a server performing reapply of updates. * It also affects our in-memory update registry mechanics. We had previously been able to assume that every update in the registry has a request payload (if the registry is lost before the update is accepted, the update is lost). But now, after a reset, we must populate the registry from mutable state, including updates with `UpdateRequested` events that must be honored. However, there might be many updates being reapplied, so we cannot load all their request payloads into memory. So, with these changes, updates in the registry may lack their request payload. This works, because such updates will have an `UpdateRequested` event, which is used as described in the preceding bullet point. #### How this was tested - PR contains functional tests and unit tests - I updated `sdk-core` to handle the new events and ran end-to-end tests of a workflow with updates and reset.
105 lines
3.7 KiB
Go
105 lines
3.7 KiB
Go
// The MIT License
|
|
//
|
|
// Copyright (c) 2024 Temporal Technologies Inc. All rights reserved.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
// THE SOFTWARE.
|
|
|
|
package resetworkflow
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/suite"
|
|
"go.temporal.io/api/enums/v1"
|
|
)
|
|
|
|
type (
|
|
resetWorkflowSuite struct {
|
|
suite.Suite
|
|
}
|
|
)
|
|
|
|
func TestResetWorkflowSuite(t *testing.T) {
|
|
s := new(resetWorkflowSuite)
|
|
suite.Run(t, s)
|
|
}
|
|
|
|
func (s *resetWorkflowSuite) TestGetResetReapplyExcludeTypes() {
|
|
// Include all with no exclusions => no exclusions
|
|
s.Equal(
|
|
map[enums.ResetReapplyExcludeType]bool{},
|
|
GetResetReapplyExcludeTypes(
|
|
[]enums.ResetReapplyExcludeType{},
|
|
enums.RESET_REAPPLY_TYPE_ALL_ELIGIBLE,
|
|
),
|
|
)
|
|
// Include all with one exclusion => one exclusion (honor exclude in presence of default value of deprecated option)
|
|
s.Equal(
|
|
map[enums.ResetReapplyExcludeType]bool{enums.RESET_REAPPLY_EXCLUDE_TYPE_SIGNAL: true},
|
|
GetResetReapplyExcludeTypes(
|
|
[]enums.ResetReapplyExcludeType{enums.RESET_REAPPLY_EXCLUDE_TYPE_SIGNAL},
|
|
enums.RESET_REAPPLY_TYPE_ALL_ELIGIBLE,
|
|
),
|
|
)
|
|
// Include signal with no exclusions => exclude updates
|
|
// (honor non-default value of deprecated option in presence of default value of non-deprecated option)
|
|
s.Equal(
|
|
map[enums.ResetReapplyExcludeType]bool{enums.RESET_REAPPLY_EXCLUDE_TYPE_UPDATE: true},
|
|
GetResetReapplyExcludeTypes(
|
|
[]enums.ResetReapplyExcludeType{},
|
|
enums.RESET_REAPPLY_TYPE_SIGNAL,
|
|
),
|
|
)
|
|
// Include signal with exclude signal => include signal means they want to exclude updates, and then the explicit
|
|
// exclusion of signal trumps the deprecated inclusion
|
|
s.Equal(
|
|
map[enums.ResetReapplyExcludeType]bool{
|
|
enums.RESET_REAPPLY_EXCLUDE_TYPE_SIGNAL: true,
|
|
enums.RESET_REAPPLY_EXCLUDE_TYPE_UPDATE: true,
|
|
},
|
|
GetResetReapplyExcludeTypes(
|
|
[]enums.ResetReapplyExcludeType{enums.RESET_REAPPLY_EXCLUDE_TYPE_SIGNAL},
|
|
enums.RESET_REAPPLY_TYPE_SIGNAL,
|
|
),
|
|
)
|
|
// Include none with no exclusions => all excluded
|
|
// (honor non-default value of deprecated option in presence of default value of non-deprecated option)
|
|
s.Equal(
|
|
map[enums.ResetReapplyExcludeType]bool{
|
|
enums.RESET_REAPPLY_EXCLUDE_TYPE_SIGNAL: true,
|
|
enums.RESET_REAPPLY_EXCLUDE_TYPE_UPDATE: true,
|
|
},
|
|
GetResetReapplyExcludeTypes(
|
|
[]enums.ResetReapplyExcludeType{},
|
|
enums.RESET_REAPPLY_TYPE_NONE,
|
|
),
|
|
)
|
|
// Include none with exclude signal is all excluded
|
|
s.Equal(
|
|
map[enums.ResetReapplyExcludeType]bool{
|
|
enums.RESET_REAPPLY_EXCLUDE_TYPE_SIGNAL: true,
|
|
enums.RESET_REAPPLY_EXCLUDE_TYPE_UPDATE: true,
|
|
},
|
|
GetResetReapplyExcludeTypes(
|
|
[]enums.ResetReapplyExcludeType{enums.RESET_REAPPLY_EXCLUDE_TYPE_SIGNAL},
|
|
enums.RESET_REAPPLY_TYPE_NONE,
|
|
),
|
|
)
|
|
}
|