VirtusLab / besom

Besom - a Pulumi SDK for Scala. Also, incidentally, a broom made of twigs tied round a stick. Brooms and besoms are used for protection, to ward off evil spirits, and cleansing of ritual spaces.
https://virtuslab.github.io/besom/
Apache License 2.0
122 stars 7 forks source link

WIP: Improve all public APIs by dropping (using Context) #538

Open lbialy opened 3 weeks ago

lbialy commented 3 weeks ago

The (using Context) clause and related context function executed in Pulumi.run are both a blessing as they make the task of propagation of the main data structure quite easy and a curse as they pollute public API with a detail that can't be used in any way by the user. @jchapuis suggested to move the main monad (from user's perspective) - the Output - towards a Kleisli-like structure and I was wary of that as it looked like it would break one of the core invariants of all async tasks being tracked by the Context to prevent early exits. There wasn't also much motivation to do such change beyond the simplification of the API but then we've got some reports about how Intellij IDEA's Scala Plugin fails to handle most of our APIs.

This PR changes Output from a wrapper over Result[OutputData[A]] to a wrapper over Context => Result[OutputData[A]]. This in turn allows us to drop (using Context) on Output constructors and demand an instance of Context only when interpreting Output to get the underlying OutputData[A] or just Option[A]. This interpretation happens in the guts of besom-core library and therefore this change should be invisible for the user (beyond the disappearance of (using Context) clause).

06.09.2024 / 70d253870470f9639a741f861bc7adc7fa2bc887 Current state is that Output was modified and all the changes to make the tests green have been applied. Task tracking is applied by registering the top-level tasks that are getting interpreted inside of the get* family of functions. The logic behind this is that since the final task waits for all tasks it composes it should be fine to do only this but this probably won't work for fire-and-forget cases where subtasks are launched in composed effects as it's possible we won't track their final Outputs at all. This is not a problem, we can modify the implementation so that all tasks are tracked the same way it was done before by just transforming the received function to track the resulting Result[OutputData[A]]. This comes at an increased memory cost but that's probably not a big deal given the amount of real parallelism that happens in Besom programs.