Skip to content

Conversation

@didier-wenzek
Copy link
Contributor

@didier-wenzek didier-wenzek commented Nov 20, 2025

Proposed changes

  • Deprecate flow script onConfigUpdate method
  • Add a context argument to onMessage and onInterval to give the scripts access to the shared data
  • context.mapper gives the scripts a read access to a store shared by all the flows
  • context.mapper is populated by regular flows which output is configured to be the context.
  • context.flow is shared by all the scripts of a flow
  • context.script is private to a script instance
  • context.config is the config provided by the flow to a script instance
  • the keys of a context can be listed with the keys method.
  • context can be updated using get, set, remove methods.

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Improvement (general improvements like code refactoring that doesn't explicitly fix a bug or add any new functionality)
  • Documentation Update (if none of the other choices apply)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

Paste Link to the issue

#3850

Checklist

  • I have read the CONTRIBUTING doc
  • I have signed the CLA (in all commits with git commit -s. You can activate automatic signing by running just prepare-dev once)
  • I ran just format as mentioned in CODING_GUIDELINES
  • I used just check as mentioned in CODING_GUIDELINES
  • I have added tests that prove my fix is effective or that my feature works
  • I have added necessary documentation (if appropriate)

Further comments

@codecov
Copy link

codecov bot commented Nov 20, 2025

Codecov Report

❌ Patch coverage is 83.45588% with 45 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
crates/extensions/tedge_flows/src/runtime.rs 21.21% 26 Missing ⚠️
...ates/extensions/tedge_flows/src/js_lib/kv_store.rs 84.21% 6 Missing and 6 partials ⚠️
crates/extensions/tedge_flows/src/js_value.rs 33.33% 4 Missing ⚠️
crates/extensions/tedge_flows/src/actor.rs 0.00% 2 Missing ⚠️
crates/extensions/tedge_flows/src/config.rs 50.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions
Copy link
Contributor

github-actions bot commented Nov 20, 2025

Robot Results

✅ Passed ❌ Failed ⏭️ Skipped Total Pass % ⏱️ Duration
744 0 3 744 100 2h22m40.638140999s

@reubenmiller reubenmiller added this to the 1.7.0 milestone Nov 24, 2025

let meta = config[`${message.topic}/meta`] || {}
let store = new FlowStore()
let meta = store.get(`${message.topic}/meta`) || {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That || {} would mask a possible race condition between this flow and the load_metadata.toml flow, right? Since both the flows could be loaded independently, this required context may not have been populated by the other flow, before this step is executed by this flow as it could theoretically receive the measurement message first, before the other flow receives and processes the metadata message for the same.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That || {} would mask a possible race condition between this flow and the load_metadata.toml flow, right?

As long as the flow mapper received the metadata first and the measurement second, then the mapper guarantees this line to be processed where the context metadata is available. But yes, a race can happen at the MQTT level - exactly as for any other mapper or agent logic.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though wouldn't the race conditional only occur for the first message? Any message delivered in the future will then be processed after the store has been populated.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though wouldn't the race conditional only occur for the first message? Any message delivered in the future will then be processed after the store has been populated.

As discussed offline, the race condition would happen not only when the flow is loaded for the very first time, but everytime the flow is reloaded as well, on mapper restarts. Even though the subscriptions made by these flows are persistent after the flow is loaded for the first time, the race between messages from two different topics can still happen whenever the MQTT connection is re-established. This is a fundamental issue with the MQTT protocol itself that we've had to workaround for the entity store, by caching telemetry messages for an entity before it is registered. The flow scripts will also have to take a similar approach by caching the data in the flow context.

/// }
/// }
/// ```
export function onConfigUpdate(message, config) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though I'm fully aligned with tedge taking over the extract and store responsibilities of the meta messages, one additional "feature" that we've lost in the process is the flows awareness of any dynamic meta changes. For example, if there was a tick based flow doing some processing with an interval of 1h, if the meta definition changed after 30 mins, the flow should have been aware of this change. The flow can choose whether to react to that change or not for the current batch of messages. But, at least getting notified would have been useful.

This is probably not a big deal in most fleets where the telemetry metadata is pretty much static.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we allow for multiple outputs? If so, then technically users could also publish the context to an MQTT topic as well, and the flow could subscribe to both the original flow messages, and the context updates (which are also published on some local MQTT topic)

Copy link
Contributor

@albinsuresh albinsuresh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy to approve once the doc is updated.

A side note, unrelated to this PR: When console.log() outputs are logged in the mapper log, it appears directly as follows:

Nov 28 06:37:49 f6641df9de15 tedge-mapper[530]: JavaScript.Console: "test log"

It would have been better if the context(module_name) of that log is also included in that log statement.


let entity_id = `${topic_parts[1]}/${topic_parts[2]}/${topic_parts[3]}/${topic_parts[4]}`
if (entity_id != "device/main//") {
let entity = context.mapper.get(entity_id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While trying to access a non-exported context namespace like context.abc.get() from the script, it was a silent failure with no trace of that error in the log. But, testing the same broken script with the tedge flows test utility was giving the proper error message:

2025-11-28T06:29:00.114082517Z ERROR tedge::cli::flows::test: Error in /etc/tedge/flows/measurements.toml: No messages can be processed due to an incorrect setting: JS raised exception: Error: cannot read property 'get' of undefined
    at onMessage (/etc/tedge/flows/measurements.toml|0|/etc/tedge/flows/add_timestamp.js:2:11)

Was it not feasible to get the same error message during live message processing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no trace of that error in the log.

This is surprising. Both tedge-mapper flows and tedge flows test should log the same. I will check.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So there is indeed a difference between tedge-mapper flows and tedge flows test.

  • tedge flows test ignores all the input, output and error configuration: all the messages are consumed from stdin and published to stdout or stderr.
  • tedge-mapper flows uses the configured input, output and error. And the default is to send errors to te/errors.

One can improve flow error logging with an option to tee error messages to the mapper log.

Copy link
Contributor

@albinsuresh albinsuresh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving with minor doc suggestions. The inconsistency with the error reporting and the logging of console.log() log statements, reported in the previous review, are independent issues. So, it can be handled separately as well.

This is first step toward a context used by flow scripts to access shared data,
such as entity metadata or measurement units. For this first step,
the store is not passed as an argument to the onMessage and onInterval method.
The scripts has to create a `new FlowStore()` providing a `get()` method
to get the value attached to some key - typically the metadata attached to an MQTT topic.

The scripts only have a read access to the shared store
which is populated by regular flows which output is configured to be the context.

Signed-off-by: Didier Wenzek <[email protected]>
Now flow script have to use the shared KV store to share data such as entity metadata or measurement units

Signed-off-by: Didier Wenzek <[email protected]>
This introduces 3 levels of namespace:

- `mapper` shared by all the flows
- `flow` shared by all the steps of a flow
- `script` private to a script instance

Signed-off-by: Didier Wenzek <[email protected]>
Signed-off-by: Didier Wenzek <[email protected]>
Copy link
Contributor

@reubenmiller reubenmiller left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved

@didier-wenzek didier-wenzek added this pull request to the merge queue Nov 29, 2025
Merged via the queue into thin-edge:main with commit 50c7eb8 Nov 29, 2025
34 checks passed
@didier-wenzek didier-wenzek deleted the feat/tedge-flows-context branch November 30, 2025 16:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants