fix: apply invocation config to workflow Data after callback - #606
fix: apply invocation config to workflow Data after callback#606danskmt wants to merge 1 commit into
Conversation
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
This comment has been minimized.
This comment has been minimized.
b804c2c to
2bb8c90
Compare
This comment has been minimized.
This comment has been minimized.
2bb8c90 to
89017c8
Compare
This comment has been minimized.
This comment has been minimized.
89017c8 to
86de328
Compare
PR Reviewer Guide 🔍
|
| // config when each key resolves to a value (including AddDefaultValue). If | ||
| // TEMP_DIR_PATH is absent, d.tempDirPath is left unchanged (typically ""), and | ||
| // os.CreateTemp uses the process default temp directory. | ||
| func WithConfiguration(config configuration.Configuration) Option { |
There was a problem hiding this comment.
in an ideal world (at least the one in my head) there should be a receiver func (d *DataImpl) WithConfiguration(...). As this may be problematic to implement now (too many usages off the task scope), I suggest the following:
func WithConfiguration(config configuration.Configuration) Option {
return func(d *DataImpl) { d.configureFrom(config) }
}
func (d *DataImpl) configureFrom(config configuration.Configuration) {
// copy in memory threshold and temp dir path if present in config
}
func (d *DataImpl) applyConfiguration(config configuration.Configuration) {
... your nil check
d.configureFrom(config)
... rest of logic from your method
}
what do you think - this doesn't change the existing signatures which is probably used from other places, while keeping the state in the receiver
|
/describe |
|
PR Description updated to latest commit (86de328) |
|
This PR does not make sense to me. Which problem are we solving? |
| // directory. This allows the engine to apply its configuration to Data | ||
| // objects that were created without WithConfiguration. | ||
| func (d *DataImpl) applyConfiguration(config configuration.Configuration) { | ||
| if config.Get(configuration.IN_MEMORY_THRESHOLD_BYTES) == nil { |
There was a problem hiding this comment.
Should-Fix (correctness): new nil-config panic path. Invoke now unconditionally calls applyConfiguration(options.config) for every *DataImpl output, and this first line dereferences the config. When a caller passes a nil config — Invoke(id, WithConfig(nil)) or the deprecated InvokeWithConfig(id, nil) — options.config is nil, so this panics (nil interface method call). Before this PR that path was harmless: the engine only stored the config (newInvocationContext, SetConfiguration) and never dereferenced it. Root-cause fix is one line at the top of this method: if config == nil { return }. Please also add a test: Invoke with WithConfig(nil) and a workflow returning NewData(...) must not panic. — AI review
| // even when workflows create Data without WithConfiguration. | ||
| for _, d := range output { | ||
| if di, ok := d.(*DataImpl); ok { | ||
| di.applyConfiguration(options.config) |
There was a problem hiding this comment.
Should-Fix (contract): engine silently overrides a workflow's explicit WithConfiguration. This loop applies the engine config to every returned *DataImpl, and applyConfiguration re-runs WithConfiguration, overwriting inMemoryThreshold/tempDirPath. A workflow that deliberately built its Data with NewData(..., WithConfiguration(customCfg)) (e.g. a higher threshold to keep a payload in memory on purpose) has that intent silently replaced by the engine defaults and force-spilled. applyConfiguration can't distinguish "never configured" (the case this PR targets) from "deliberately configured". Either apply only when the Data was never configured, or document on Invoke that engine config always wins last. This override path is also untested (new tests only cover Data created without WithConfiguration). — AI review
| // Apply the engine's configuration to output data so that | ||
| // IN_MEMORY_THRESHOLD_BYTES and TEMP_DIR_PATH are respected | ||
| // even when workflows create Data without WithConfiguration. | ||
| for _, d := range output { |
There was a problem hiding this comment.
Suggestion: relocation runs even when the callback returned an error. This loop is outside any if err == nil guard, so when a workflow returns partial output alongside a non-nil err, that soon-to-be-discarded output is still spilled to disk, leaving orphan temp files for data nobody consumes. Guarding the loop with if err == nil avoids the wasted I/O. — AI review
| return func(d *DataImpl) { | ||
| d.inMemoryThreshold = config.GetInt(configuration.IN_MEMORY_THRESHOLD_BYTES) | ||
| d.tempDirPath = config.GetString(configuration.TEMP_DIR_PATH) | ||
| if v := config.Get(configuration.IN_MEMORY_THRESHOLD_BYTES); v != nil { |
There was a problem hiding this comment.
Suggestion: exported-API semantic change worth a direct-caller test. WithConfiguration previously set inMemoryThreshold/tempDirPath unconditionally (unset key → 0/""); it now skips a key when config.Get(...) == nil. This is a genuine fix (an unset threshold no longer means "spill everything"), but WithConfiguration is public and no test asserts the new behavior for direct external callers when one key is set and the other is unset. Any caller that relied on "unset threshold ⇒ 0 ⇒ spill" changes silently. Add a focused unit test for the mixed set/unset case. — AI review
PR #606 — apply invocation config to output Data after callback Overall: solid, focused fix with good test coverage for the intended path (relocation, threshold-disabled, key-absent, Should-Fix (see inline):
Suggestions (see inline):
Minor (no inline):
— AI review |
User description
Description
Workflows can return
Datacreated withworkflow.NewDatawithoutWithConfiguration, soIN_MEMORY_THRESHOLD_BYTESandTEMP_DIR_PATHwere not applied to those payloads.After each workflow callback returns,
EngineImpl.InvokecallsapplyConfigurationon each*DataImplin the output slice so in-memory payloads can spill to the configured temp directory when above threshold.applyConfigurationis package-private onDataImpl(same package as the engine) so it is not exported from the workflow package.Adds tests in
dataimpl_test.gofor spill and no-op cases, and inengine_test.gofor behavior afterInvoke.Checklist
make test)make generate)make lint)go get github.com/snyk/go-application-framework@YOUR_LATEST_GAF_COMMITin thecliv2directory.go.modto point to your local GAF code.go mod tidyin thecliv2directory.go.modandgo.sumchanges.PR in CLI snyk/cli#6792
Where reviewers should start
pkg/workflow/dataimpl.go—applyConfigurationpkg/workflow/engineimpl.go— post-process loop aftercallbackRisk assessment
Low. Default production behavior is unchanged unless spill-related settings are enabled; when they are, returned
Dataplacement aligns with engine configuration instead of leaving eligible payloads in memory.PR Type
Bug fix, Enhancement, Tests
Description
Apply engine configuration to workflow output Data.
Enable payload spilling based on engine settings.
Introduce
DataImpl.applyConfigurationmethod logic.Add comprehensive tests for configuration application.
Diagram Walkthrough
File Walkthrough
dataimpl.go
Implement DataImpl configuration application logicpkg/workflow/dataimpl.go
WithConfigurationto conditionally apply threshold and tempdir values.
applyConfigurationmethod to relocate in-memory payloads todisk based on configuration.
dataimpl_test.go
Add tests for DataImpl applyConfigurationpkg/workflow/dataimpl_test.go
applyConfiguration.missing temp directory paths.
engine_test.go
Test engine Invoke output configuration applicationpkg/workflow/engine_test.go
Test_Invoke_AppliesConfigurationToOutput.data, causing spills.
engineimpl.go
Apply engine configuration to Invoke outputpkg/workflow/engineimpl.go
Invoketo iterate over workflow outputData.di.applyConfiguration(options.config)on eachDataImplto applyengine settings.