Comments (9)
Hello,
No plans. The main idea for the Ohm::Transaction model is to simply assist in simpler scenarios. For more complicated scenarios where dependencies and ordering is important, it's much simpler to script your transaction in Lua, and that's what we're doing in our applications.
from ohm.
Well, simpler is better of course, but only after the app works. I think I've given you a very simple and common scenario here above which it doesn't seem the currently proposed Ohm::Transaction mechanism can handle. Composition is cool but nesting is necessary when combining classes that need to commit state together but otherwise have no knowledge of each other.
Sure, we could write this in Lua or SQL for that matter but the whole point of Ohm is to reduce the complexity of our applications and adding another language to the chain is something we absolutely don't want to do. Although the layering may make the implementation simpler, it adds a lot of support overhead.
Rather, it's great if the Ohm layer provides an efficient transaction mechanism which may in part be implemented in Lua (we do not view Redis as an app dependency by the way; rather Ohm is supposed to be a more complete abstraction on the datastore.) And we should not need to code Lua to make simple multiobject and nested transactions work correctly with Ohm.
How about you illustrate the types of scenarios/use cases that the Ohm::Transaction mechanism is supposed to handle, and specifically the commit A -> commit B -> commit C scenario as above. Then we could proceed concretely. Seems like there would need to be a TransactionManager and some protocol for this to work but we want to keep the code of each persisted class 'simple'. Maybe you have a better idea?
from ohm.
Hmm well specifically nesting transactions isn't really something that happens in reality, even with SQL.
C needs B needs A is such an abstract example that it's not practical for us to think of a solution for it at this point.
It's much simpler to do reads, and then write all of the data gathered up, and that's it. If for some reason a different set of reads needs another set of reads, then why not just read them both in one block?
The reason for optimizing to Lua isn't a crutch either. Transactions that grow big doing optimistic locking have a very very poor performance profile. The reason for which is if you do 10 reads, and the transaction fails, then you have to do all of them all over again, and it is not deterministic when you'll finally get the chance to finally commit the transaction.
The way we see it, depending in your isolation levels, you have to use whichever fits the bill. Locking / CAS / Lua.
Thanks,
cyx
from ohm.
That all makes good sense, but what we're talking about is really a kind of lexical nesting, not sub-transactions:
If for some reason a different set of reads needs another set of reads, then why not just read them both in one block?
Let's say this is a request-based web application. It uses models composed from several modules/components/gems whatever. Let's say the models are 'transaction aware' to the level of Ohm::Transaction, so that e.g. A.op1
runs an Ohm::Transaction to do its updates and B.op2
similarly uses Ohm::Transaction for its updates which are atomic within the scope of each model. From the point of view of the application however, each model's updates must happen atomically together, i.e. either A&B commit or neither. From the developer's perspective we would like to have the transaction be 'automatically' request-scoped and ideally not even need anything explicit at the controller layer.
But even with explicitly starting the transaction in the controller, how would you propose composing this generally? While preserving the notion that A.op1 and B.op2 are each independently atomic, and we want to preserve the encapsulation of each model and not push model-specific logic into the controller. Further, each of these atomic model ops may invoke other model classes atomic ops, e.g. C.op3 unbenknownst to the controller. So illustrate how the composition could work with the current Ohm::Transaction sketch.
Also I'm not saying that doing it on the Lua side is bad, only that it should happen automatically from the perspective of the app developer.
from ohm.
So let's say module A, B, and C has a method txn
that returns a transaction.
We can do this:
transaction = Transaction.new
transaction.append(A.txn)
transaction.append(B.txn)
transaction.append(C.txn)
transaction.commit(Ohm.redis)
All of the transactions at this point will happen all-or-nothing.
We're just against complecting transactions by making them aware of each other. As far as
appending them together and making them run in one go, that's what we targetted with the current design.
Thanks,
cyx
On Mar 26, 2012, at 2:17 PM, tribalvibes wrote:
That all makes good sense, but what we're talking about is really a kind of lexical nesting, not sub-transactions:
If for some reason a different set of reads needs another set of reads, then why not just read them both in one block?
Let's say this is a request-based web application. It uses models composed from several modules/components/gems whatever. Let's say the models are 'transaction aware' to the level of Ohm::Transaction, so that e.g.
A.op1
runs an Ohm::Transaction to do its updates andB.op2
similarly uses Ohm::Transaction for its updates which are atomic within the scope of each model. From the point of view of the application however, each model's updates must happen atomically together, i.e. either A&B commit or neither. From the developer's perspective we would like to have the transaction be 'automatically' request-scoped and ideally not even need anything explicit at the controller layer.But even with explicitly starting the transaction in the controller, how would you propose composing this generally? While preserving the notion that A.op1 and B.op2 are each independently atomic, and we want to preserve the encapsulation of each model and not push model-specific logic into the controller. Further, each of these atomic model ops may invoke other model classes atomic ops, e.g. C.op3 unbenknownst to the controller. So illustrate how the composition could work with the current Ohm::Transaction sketch.
Also I'm not saying that doing it on the Lua side is bad, only that it should happen automatically from the perspective of the app developer.
Reply to this email directly or view it on GitHub:
#49 (comment)
from ohm.
Right, not to overcomplixify this. I think the composition could work as-is or with a simple modification to the mechanism. We just want to avoid writing the block as you've done requiring the knowledge of all of the components' (and subcomponents') transactions to be centralised. Rather these could be pushed via a coordinator. We'll just follow our app needs and if it seems there should be a component or another layer for this we'll add it.
Cheers,
.tv/
from ohm.
@soveran last night pushed a change that ensures the order of execution of reads and writes. This in itself isn't the solution you're looking for in it's entirety, but it's a good starting point which doesn't incur any form of complexity or performance penalties.
With the latest master, you can compose transactions with the guarantee that previously appended transactions will always execute before transactions appended after.
Thanks,
cyx
from ohm.
@cyx Is this still valid or can be closed?
from ohm.
@soveran Same as #53. Ohm::Transaction has been removed from Ohm 2. Beyond that, apparently this issue was solved but not close it.
from ohm.
Related Issues (20)
- Models load order causing reference errror HOT 1
- Model.find for attributes with long integers fails HOT 7
- Finding parent for child objects in list? HOT 5
- Public API for @_memo?
- ConnectionPool support HOT 1
- Race condition on list delete HOT 1
- connection.rb:11: [BUG] Segmentation fault at 0x0000000000000000 HOT 5
- Search by part HOT 1
- Does Entry.find has a default sort strategy? HOT 1
- Feature Suggestion: `Ohm::Model::fetch` for uniques? HOT 2
- Rails 5.2.0 - When Oj integrates with Rails, it modifies JSON and breaks Ohm HOT 21
- Ignoring Redis fields that are missing in the model? HOT 4
- Getting last id HOT 6
- Ohm on Windows HOT 11
- Infrequent and weird #<RuntimeError: NOAUTH Authentication required> in heroku/rediscloud environment HOT 42
- Deleted Items Remain in Set HOT 2
- Order in Collections
- Distribute updates to multiple Redis instances
- Enabling GitHub Discussions HOT 1
- Is this library still supported? HOT 1
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 ohm.