thin-edge / thin-edge.io

The open edge framework for lightweight IoT devices
https://thin-edge.io
Apache License 2.0
211 stars 55 forks source link

Simplify the operation handling code by replacing fragmented control flow with regular async/await #2881

Closed Bravo555 closed 1 month ago

Bravo555 commented 1 month ago

Proposed changes

This PR should make the operation handle simpler to reason about and change, by allowing operation handlers to use .await without blocking. The scope of the PR is to show the idea working on the config_snapshot and config_update operations.

Below i describe the current state, which is subject to change.

  1. In 6b90d51e4420dbfe5cd7906bcf57e48494e9ae4e, the main C8y mapper actor is prepared for its messages to be handled concurrently in separate tasks. For now, we use Mutexes to guard the MqttPublisher and CumulocityConverter:
    • using wrapper struct MqttPublisher(Arc<Mutex<LoggingSender<MqttMessage>>>) with fn send(&self) is ok, as we lock the mutex to use the sender, and unlock it immediately after we finished sending, so it shouldn't block. The alternative would be to clone the sender for each worker, and I will explore it later.
    • with Mutex<CumulocityConverter>, it ensures that only a single worker can use CumulocityConverter at any given time, which can lead to deadlocks if we're not careful, and currently results in the same behaviour as before, i.e. blocking in the operation handling code will block processing of other messages, because the lock will be open across await points. This is temporary, and will have to be fixed, but is used right now so I could show how the full operation handling function would look like, without the current fragmentation. Also, the test demonstrating that the converter doesn't block should be made.
  2. In 72dc9d09bb644758c4684253ee8f276d53168666, I export Identity type from the download crate, so I can use it in the next commit.
  3. In 0e8656851b2fb1d9be90021ef0feab33d9d7d818, Downloader is used directly in the operation handler, to show how we can use it directly without going through the actor: if we only want to download a file via HTTP, and this download shouldn't influence anything else, we can use it directly.
  4. In 892ecbec71a21a9e9bc93252f27abdac4057390d we use UploaderActor via ClientMessageBox, where we receive the response directly in the same place where we send(), instead of going to the top-level receiver in the top-level actor, which then needs to decide to call an operation handling function again. This way we still use an uploader actor, and have messages sent between them, but don't need to fragment our control flow. This was done to show that we can still send and receive messages from other actors from within the proposed new operation handlers.

Next steps

Types of changes

Paste Link to the issue

Checklist

Further comments

codecov[bot] commented 1 month ago

Codecov Report

Attention: Patch coverage is 79.90431% with 42 lines in your changes are missing coverage. Please review.

Project coverage is 77.9%. Comparing base (644cd6f) to head (f5f7511). Report is 6 commits behind head on main.

:exclamation: Current head f5f7511 differs from pull request most recent head 884b25f

Please upload reports for the commit 884b25f to get more accurate results.

Additional details and impacted files | [Files](https://app.codecov.io/gh/thin-edge/thin-edge.io/pull/2881?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=thin-edge) | Coverage Δ | | |---|---|---| | [crates/common/download/src/download.rs](https://app.codecov.io/gh/thin-edge/thin-edge.io/pull/2881?src=pr&el=tree&filepath=crates%2Fcommon%2Fdownload%2Fsrc%2Fdownload.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=thin-edge#diff-Y3JhdGVzL2NvbW1vbi9kb3dubG9hZC9zcmMvZG93bmxvYWQucnM=) | `81.3% <ø> (+0.6%)` | :arrow_up: | | [crates/core/tedge\_api/src/lib.rs](https://app.codecov.io/gh/thin-edge/thin-edge.io/pull/2881?src=pr&el=tree&filepath=crates%2Fcore%2Ftedge_api%2Fsrc%2Flib.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=thin-edge#diff-Y3JhdGVzL2NvcmUvdGVkZ2VfYXBpL3NyYy9saWIucnM=) | `100.0% <ø> (ø)` | | | [crates/extensions/c8y\_mapper\_ext/src/tests.rs](https://app.codecov.io/gh/thin-edge/thin-edge.io/pull/2881?src=pr&el=tree&filepath=crates%2Fextensions%2Fc8y_mapper_ext%2Fsrc%2Ftests.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=thin-edge#diff-Y3JhdGVzL2V4dGVuc2lvbnMvYzh5X21hcHBlcl9leHQvc3JjL3Rlc3RzLnJz) | `92.6% <100.0%> (+<0.1%)` | :arrow_up: | | [...nsions/c8y\_mapper\_ext/src/operations/log\_upload.rs](https://app.codecov.io/gh/thin-edge/thin-edge.io/pull/2881?src=pr&el=tree&filepath=crates%2Fextensions%2Fc8y_mapper_ext%2Fsrc%2Foperations%2Flog_upload.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=thin-edge#diff-Y3JhdGVzL2V4dGVuc2lvbnMvYzh5X21hcHBlcl9leHQvc3JjL29wZXJhdGlvbnMvbG9nX3VwbG9hZC5ycw==) | `90.2% <94.7%> (-0.1%)` | :arrow_down: | | [crates/extensions/c8y\_mapper\_ext/src/config.rs](https://app.codecov.io/gh/thin-edge/thin-edge.io/pull/2881?src=pr&el=tree&filepath=crates%2Fextensions%2Fc8y_mapper_ext%2Fsrc%2Fconfig.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=thin-edge#diff-Y3JhdGVzL2V4dGVuc2lvbnMvYzh5X21hcHBlcl9leHQvc3JjL2NvbmZpZy5ycw==) | `47.8% <50.0%> (+<0.1%)` | :arrow_up: | | [crates/extensions/c8y\_mapper\_ext/src/converter.rs](https://app.codecov.io/gh/thin-edge/thin-edge.io/pull/2881?src=pr&el=tree&filepath=crates%2Fextensions%2Fc8y_mapper_ext%2Fsrc%2Fconverter.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=thin-edge#diff-Y3JhdGVzL2V4dGVuc2lvbnMvYzh5X21hcHBlcl9leHQvc3JjL2NvbnZlcnRlci5ycw==) | `83.4% <84.0%> (-0.3%)` | :arrow_down: | | [...es/extensions/c8y\_mapper\_ext/src/operations/mod.rs](https://app.codecov.io/gh/thin-edge/thin-edge.io/pull/2881?src=pr&el=tree&filepath=crates%2Fextensions%2Fc8y_mapper_ext%2Fsrc%2Foperations%2Fmod.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=thin-edge#diff-Y3JhdGVzL2V4dGVuc2lvbnMvYzh5X21hcHBlcl9leHQvc3JjL29wZXJhdGlvbnMvbW9kLnJz) | `91.0% <73.3%> (-1.5%)` | :arrow_down: | | [crates/extensions/c8y\_mapper\_ext/src/actor.rs](https://app.codecov.io/gh/thin-edge/thin-edge.io/pull/2881?src=pr&el=tree&filepath=crates%2Fextensions%2Fc8y_mapper_ext%2Fsrc%2Factor.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=thin-edge#diff-Y3JhdGVzL2V4dGVuc2lvbnMvYzh5X21hcHBlcl9leHQvc3JjL2FjdG9yLnJz) | `80.4% <80.5%> (-2.0%)` | :arrow_down: | | [...s/c8y\_mapper\_ext/src/operations/config\_snapshot.rs](https://app.codecov.io/gh/thin-edge/thin-edge.io/pull/2881?src=pr&el=tree&filepath=crates%2Fextensions%2Fc8y_mapper_ext%2Fsrc%2Foperations%2Fconfig_snapshot.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=thin-edge#diff-Y3JhdGVzL2V4dGVuc2lvbnMvYzh5X21hcHBlcl9leHQvc3JjL29wZXJhdGlvbnMvY29uZmlnX3NuYXBzaG90LnJz) | `78.4% <76.9%> (-12.2%)` | :arrow_down: | ... and [1 file with indirect coverage changes](https://app.codecov.io/gh/thin-edge/thin-edge.io/pull/2881/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=thin-edge)
github-actions[bot] commented 1 month ago

Robot Results

:white_check_mark: Passed :x: Failed :next_track_button: Skipped Total Pass % :stopwatch: Duration
435 1 3 436 99.77 56m13.273314s

Failed Tests

Name Message :stopwatch: Duration Suite
Entities persisted and restored ValueError: invalid literal for int() with base 10: '' 65.819 s Registration Lifecycle
Bravo555 commented 1 month ago

Closing in favour of #2904, which is a more promising and feasible approach.