Comments (10)
BTW, have you seen Cycle.js ? It uses Observables from Rx to manage flow and side effects
Yes looked at it. I'm a big fan of reactive Streams. I did some experimentations on building UI using Dataflow approach offered by Observables but ended up each time with a lot of complexity (lots of signals, flow hard to reason about), plus any dynamic behavior (dynamic signal graph) involved much complex monadic manipulations (flatmap and family). Didn't looked in more detail to Cycle but it seems to solve the complex flow issue by organizing signals (Observables) into separate components.
Now I switched to the Dark side :) (i.e. the pull approach)
I think @yelouafi will at some point want to provide extension points for the interpreter so that users will be able to plug their own effects.
Yeah, the idea crossed my mind, but I found myself replicating the Redux middleware funcionalities. One can build the effect interpreter as a Redux middleware and then use put(effect)
to execute the effect.
But your proposition makes quite sens if the sagas are used outside of Redux
from redux-saga.
@DjebbZ I initially suggested to @yelouafi the saga pattern that is already used in backend's eventsourcing architectures. (long discussion here paldepind/functional-frontend-architecture#20)
Also some basic implementations I provided on top of Redux:
http://stackoverflow.com/a/33501899/82609
http://stackoverflow.com/a/33829400/82609
Some doc of the Saga pattern: https://msdn.microsoft.com/en-us/library/jj591569.aspx
Actually Sagas implemented here are more "process managers" but they are often called Saga too (this is a bit confusing yes)
What I mean here is that Saga / process manager is a pattern for which there are many possible implementations. In the backend it's not rare to see the Saga being implemented as an Actor with Scala/Akka or Erlang, or many other solutions.
Here is a Java implementation of the Axon framework just to illustrate. You can see it does not look at all the same as the implementation provided by this repo (also because the domain of a backend app is very different of a frontend app):
public class OrderManagementSaga extends AbstractAnnotatedSaga {
private boolean paid = false;
private boolean delivered = false;
private transient CommandGateway commandGateway;
@StartSaga
@SagaEventHandler(associationProperty = "orderId")
public void handle(OrderCreatedEvent event) {
// client generated identifiers (1)
ShippingId shipmentId = createShipmentId();
InvoiceId invoiceId = createInvoiceId();
// associate the Saga with these values, before sending the commands (2)
associateWith("shipmentId", shipmentId);
associateWith("invoiceId", invoiceId);
// send the commands
commandGateway.send(new PrepareShippingCommand(...));
commandGateway.send(new CreateInvoiceCommand(...));
}
@SagaEventHandler(associationProperty = "shipmentId")
public void handle(ShippingArrivedEvent event) {
delivered = true;
if (paid) {
end(); (3)
}
}
@SagaEventHandler(associationProperty = "invoiceId")
public void handle(InvoicePaidEvent event) {
paid = true;
if (delivered) {
end(); (4)
}
}
// ...
}
I don't know so much the specificity of CSP and I may be wrong but the thing is @yelouafi wants to keep the effects being declarative because it makes it much easier to test (no mock required). When you use the CSP operations, it seems to me that the operation is executed right now (right?), while with the @yelouafi implementation the operations are executed in some kind of interpreter proc.js a bit like a free-monad script.
We can discuss this in next reactjs paris meetup :)
from redux-saga.
@DjebbZ Right now it looks like there is only 1 channel defined which is the Redux Store'actions (in && out).
When I defined the fork/join tasks. I considered the idea of using other channels in order to allow concurrent tasks inter-communication. But I think this would make it hard to reason about the actual control flow of the program. I prefer the structured programming approach (routine/subroutine) which makes the control flow more explicit and easy to track.
Eventually, we'd have to provide some synchronization mechanism between forked tasks. I'm still thinking about it, But I'm more willing to a more restrictive approach like some pipe
operation to connect one Task's output to another Task's Input.
from redux-saga.
Thanks @slorber for link to the (long) discussion. My understanding is that Sagas are a way to represent side-effect as pure data (declaratively) and let a special runtime/manager execute them. In this case CSP can be viewed as an implementation detail of the manager. Could use callbacks, Promises, whatever. Am I right ?
With regards to synchronization between forked tasks @yelouafi, indeed channels may make flow harder to reason about when there's a lot of them but they provide all the power to handle async cases. I hope you'll find a way to synchronise them, because handling any complex async flows declaratively would be just awesome.
BTW, have you seen Cycle.js ? It uses Observables from Rx to manage flow and side effects. In Cycle, the program is a pure function from input Observables to output Observables. You get the testability benefit from Saga, and while not completely declarative (flows are not data, they're operators on Observables), you get some "declarativeness" since each Observable must declare all the other Observables it uses and no one can change this from the outside. I know that Cycle.js auhor is working on generating flow diagrams from code just by reading the Observables declaration.
Makes me think : all declarative is nice to read/write but always seems limiting, whereas full imperative/functional is limitless but can lead to spaghettis. Sagas seem to be somewhat in the middle ground. Is it because it's impossible to have both ? Are we using the wrong paradigms ? Is it a limitation of the language ? Should we all move to LISP (half a joke, really) ? Or Dedalus (watch this GREAT talk, you'll understand my point on languages) ?
from redux-saga.
@DjebbZ yes i think the proc to use promises is an implementation detail.
Makes me think : all declarative is nice to read/write but always seems limiting, whereas full imperative/functional is limitless but can lead to spaghettis. Sagas seem to be somewhat in the middle ground. Is it because it's impossible to have both ? Are we using the wrong paradigms ? Is it a limitation of the language ? Should we all move to LISP (half a joke, really) ? Or Dedalus (watch this GREAT talk, you'll understand my point on languages) ?
I think @yelouafi will at some point want to provide extension points for the interpreter so that users will be able to plug their own effects.
If you can build your own AST and its interpreter than you are free to do whatever you want, and Redux-saga can provide some nice and useful defaults that make sense in most cases.
from redux-saga.
@yelouafi In my understanding, CSP works in blocking approach. Every put
holds until the message is take
-ed by another process. Every take
holds until there is message put
into the channel.
In Redux-saga, the Store is the global channel, but take
and put
don't work in blocking approach. This makes Redux-saga not actually CSP. Am I correct?
from redux-saga.
@mocheng as far as I can tell, redux-saga is most like CSP with a single channel. put
and take
block the current saga ("coroutine" in CSP terms):
- Calling
take(actionType)
blocks the current saga until an action withactionType
is dispatched - Calling
put(action)
immediately dispatches the action, causing the store state to be synchronously updated. Any lines of code in a saga after aput
are executed afteraction
is processed by the reducer and the store is in its next state.
from redux-saga.
put
effect is not exactly synchronous, you can look on how its handled here - https://github.com/yelouafi/redux-saga/blob/e18dfa2592b493d91b82ef68d026e311827a34ba/src/internal/proc.js#L382
from redux-saga.
@Andarist thanks for the correction. I think the main point stands, however, which is that put
blocks (The next line of code in the saga doesn't run until after the reducer has done its work). Not 100% sure, but I tested with some small examples.
from redux-saga.
In CSP,the write to the channel is blocking until there's someone read it.
but in REDUX-SAGA, put/dispatch is not blocking, if there's no one take it, the message(action) will be dropped by default.
If you use action channel,it acts more like CSP.
that's my understanding.
from redux-saga.
Related Issues (20)
- Waiting for an action with takeMaybe / take after END is dispatched for SSR HOT 7
- Is it possible to selectively cancel tasks in an actionChannel? Ie cancel the 3rd task out of 5 running ones. HOT 5
- Is it possible for a saga to "trace" the effect "chain"? HOT 4
- Delay inside of while loop may never fire with React Native 0.71.6 HOT 2
- UI freezes when chrome devtools is open HOT 4
- Redux 4.0 - Unable to access updated data using useSelector HOT 2
- could we add leading/trailing edge options for debounce? HOT 3
- Workflow has flaw
- Why not use the await and async instead of the generator and yield? HOT 1
- TS2345 error while putting thunk actions
- React native Redux Saga with Redux Tollkit
- Module '"redux-saga/effects"' has no exported member 'call'. HOT 4
- Is there a standard way to break while true loops with call effect when END is dispatched? HOT 1
- Can put type improvements be released downstream? HOT 2
- Sending very large files, tasks in parallel are using a lot of memory
- How to use package that use redux-saga as dependency when its in webpack externals? HOT 7
- Help me connect redux-saga with Nextjs 13.5 using app router HOT 2
- Update peer dependencies to include `redux@5` (currently beta) HOT 14
- feature request: interface for integration with other frameworks (like Vue) HOT 2
- Redux saga is not working in apps script react js project HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from redux-saga.