Skip to content
This repository has been archived by the owner on Jun 6, 2024. It is now read-only.

Higher order sagas #165

Closed
pinguinjkeke opened this issue Feb 21, 2023 · 2 comments
Closed

Higher order sagas #165

pinguinjkeke opened this issue Feb 21, 2023 · 2 comments

Comments

@pinguinjkeke
Copy link

Thanks for a cool library, but we often get indentation hell

saga {
    saga({
       CoroutineScope(Dispatchers.IO).run {
            retry(5) {
                async {
                    doSomething()
                }
            }
        }
    }) {
        // same levels of nesting on rollback
    }
}

It will be good to have an ability to somehow wrap saga for:

  • coroutine scopes and async calls
  • functions like retry

What do you think?

@nomisRev
Copy link
Owner

Hey @pinguinjkeke,

Thanks for the feedback! That pattern seems dangerous :/ In your snippet both the async and CoroutineScope will leak.
To solve that I think this should be written as:

saga {
    saga({
       withContext(Dispatchers.IO)  {
            retry(5) { doSomething() }
        }
    }) {
        // same levels of nesting on rollback
    }
}

It doesn't entirely resolve you problem, but it already makes the indentation a bit smaller. I see you also have indentation configured to 4-spaces, which I am personally not a fan of especially in Kotlin which can be quite heavy on DSLs.
The goal of these monadic DSLs is that they can be safely nested, but that indeed brings some callback-hell style code into play.

Albeit that with callback-hell you can never "escape" the callback, but in this case at some point you'll get the result on the lefthand side like regular imperative code. So this can typically be "solved" in Kotlin by applying some best-practices when working with suspend but doesn't entirely solve this issue of nesting.

For example:

saga {
  val result = doSomething()
}

suspend fun SagaEffect.doSomething(): A = saga({
  withContext(Dispatchers.IO) {
    retry(5) { doSomething() }
  }
}) {  // same levels of nesting on rollback  }

To come back to your original question of "higher order", it will introduce a lot of specialised code in every type similar to Saga for example CircuitBreaker has these similar concerns of CoroutineScope, withContext and retry. The benefit of Kotlin, and its suspend DSLs` is that these can all be nested and composed without having to build separate and duplicated APIs. Which in turn also increases the API surface of every library.

Not sure if my reply helps you in any way, but I think this is out of the scope of this library. Feel free to reply, or ask any questions you might have.

@pinguinjkeke
Copy link
Author

Thanks for the detailed answer.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants