Ember.js Data Conflict Resolution / Failing on Conflict - javascript

If using Ember.js with the ember-data REST adapter, is there some sort of conflict resolution strategy for handling persisting data to the server?
At the very least, for my case, failing and rolling back would be sufficient in the case of conflicts, if the user can be informed of this. So, would sort of data/structure would be required for this? Some sort of "version" id on the models, where the server can check the submitted versions, and make sure that the client had the most recent data. Is there anything in Ember.js to make this a bit less manual? And if so, what?
Edit: Also, is there anything that helps with conflicts of bulk commits of models? Say we have a parent model with a "hasMany" relationship to several child models, and all of them are to be persisted to the database at the same time. If just dealing with server-side code, I feel I could wrap this up on a transaction in whatever database I'm using, and fail if something is out of date. How does this translate to Ember.js transactions?
I see a flag bulkCommit in the Adapter class. This seems to be able to bulk commit objects of the same type, in one request. However, if I'm persisting records of more than one type, then this would result in multiple requests to the server. Is there a way to either a) make this happen in one request to the server, or b) match up ember-data's transactions with transactions on the server, so if the transaction on the server fails, and needs to be rolled back, the ember-data transaction fails as well?
[I'm evaluating Ember.js for an upcoming project, and testing a few features and what it's like to develop in. I'm actually considering more real-time updates using socket.io or similar. I see derby.js has made some movements towards automatic conflict resolution]

As you can see in the Ember Data source code here, you can return 422 HTTP status code with errors as dictionary. Errors will be added to the model by Ember Data library by key as model's property and the model itself will be considered invalid. Model will automatically leave this state once each property with errors on them changed.
You could watch for errors on version property and reloadRecord once concurrency error appears.

Related

Database cluster - asynchronous tasks

Let's say I have a couchDB database called "products" and a frontend with a form.
Now if a user opens a document from this database in the form I want to prevent other user from editing this specific document.
Usually pretty simple:
-> read document from couchDB
-> set a variable to true like: { edit : true }
-> save (merge) document to couchDB
-> if someone else tries to open the document he will receive an error, becaus of edit:true.
BUT, what if two user open the document at the exact same time?
The function would be called twice and when the second one opens the document he would falsely receive an edit:false because the first didn't had enough time to save his edit:true. So how to prevent this behaviour?
First solution would be:
Build an array as a cue for database requests and dont allow parallel requests, so all requests would be worked off one after another. But in my opinion this is a bad solution because the system would be incredible slow at some point.
Second solution:
Store the documentIDs of the currently edited documents in an local array in the script. This would work because this is no asynchronous process and the second user would receive his error immediately.
So far so good, BUT, what if some day there are too many user and this system should run in a cluster (the node client server, not the database) - now the second solution would not work anymore because every cluster slave would have its own array of documentIDs. Sharing there would end in another asynchronous task and result in the same problem above.
Now i'm out of ideas, how do big clustered systems usually handle problems like that?
CouchDB uses MVCC to maintain consistency in your database. When a document is being updated, you must supply both the ID (_id) and revision number (_rev) otherwise your change will be rejected.
This means that if 2 clients read the document at revision 1 and both attempt to write a change using that same revision number, only the first will be accepted by the database. The 2nd client will receive an error, and it should fetch the latest revision of the document in order to proceed.
In a single-node environment, this model prevents conflicts outright. However, in cases where replication is occurring, it is still possible to get conflicts, even when using MVCC. This is because conflicting revisions can technically be written to different nodes before they have been replicated to one another. In this case, CouchDB will record the conflict and your application is responsible to resolve them.
CouchDB has stellar documentation, in particular they have an article all about conflicts and replication that I highly recommend for this subject.

Deleting database entries and AngularJS. Should I throw an exception if an entry can't be deleted?

So I have an AngualrJS application that is acting as a single-page-application (SPA). This SPA is using an existing Rails API to make xhr requests which returns entries from the database as JSON.
I am currently trying to write some code to handle possible server responses. The first one that came to mind was a request to delete an entry with a one-to-many relationship. For example:
def Library < ActiveRecord::Base
has_many books
end
Would be my Rails model. In my case, I don't allow the user to destroy libraries if they currently have books. The controller will respond with some sort of appropriate status, possibly a flag in the response header. The view then responds with a message to the user that the library still has books and cannot be deleted until the books are removed.
So my question is about exception handling. If I am to follow the oft paraphrased:
Exceptions are for exceptional cases.
I am lead to the conclusion that this should not be an exceptional case because it is expected that the user will occasionally try to delete a library with books. Furthermore, the program accounts for this and has a message prepared for this case. Am I right to not consider this an exception?
For those of you that are deep into AngularJS, when do you actually use exceptions in practice?
Also, I think it's important to note that because of the asynchronous nature of the xhr requests I am using promise-chaining to handle the exceptions with .then, .catch, $q.reject etc. Which I'm still new to and don't fully understand its relationship to exceptions.
I also would not handle this as an exception. My method would be to log it with warning level on server side and show the error message in the view on client side.
I would not consider me an expert, but I think exceptions should never appear as feedback on client side if it is a productive application, because the user should not be forced to look into the console to search for errors.
If the error is a considered one like yours just show an error message.
If it is anchored in your methods and only appears in cases which should not happen during an usual use, you should throw an exception so you know what happened. But you should also show some feedback in the view for the user.

How to integrate Redux with very large data-sets and IndexedDB

I have an app that uses a sync API to get its data, and requires to store all the data locally.
The data set itself is very large, and I am reluctant to store it in memory, since it can contains thousands of records. Since I don't think the actual data structure is relevant, let's assume I am building an email client that needs to be accessible offline, and that I want my storage mechanism to be IndexedDB (which is async).
I know that a simple solution would be to not have the data structure as part of my state object and only populate the state with the required data (eg - store email content on state when EMAIL_OPEN action is triggered). This is quite simple, especially with redux-thunk.
However, this would mean I need to compromise 2 things:
The user data is no longer part of the "application state", although in truth it is. Since the sync behavior is complex, and removing it from the app state machine will hurt the elegance of the redux concepts (the way I understand them)
I really like the redux architecture and would like all of my logic to go through it, not just the view state.
Are there any best-practices on how to use redux with a not-in-memory state properties? The thing I find hardest to wrap my head around is that redux relies on synchronous APIs, and so I cannot replace my state object with an async state object (unless I remove redux completely and replace it with my own, async implementation and connector).
I couldn't find an answer using Google, but if there are already good resources on the subject I would love to be pointed out as well.
UPDATE:
Question was answered but wanted to give a better explantation into how I implemented it, in case someone runs into it:
The main idea is to maintain change lists of both client and server using simply redux reducers, and use a connector to listen to these change lists to update IDB, and also to update the server with client changes:
When client makes changes, use reducers to update client change list.
When server sends updates, use reducers to update server change list.
A connector listens to store, and on state change updates IDB. Also maintain internal list of items that were modified.
When updating the server, use list of modified items to pull delta from IDB and send to server.
When accessing the data, use normal actions to pull from IDB (eg using redux-thunk)
The only caveat with this approach is that since the real state is stored in IDB, so we do lose some of the value of having one state object (and also harder to rewind/fast-forward state)
I think your first hunch is correct. If(!) you can't store everything in the store, you have to store less in the store. But I believe I can make that solution sound much better:
IndexedDB just becomes another endpoint, much like any server API you consume. When you fetch data from the server, you forward it to IndexedDB, from where your store is then populated. The store gets just what it needs and caches it as long as it doesn't get too big or stale.
It's really not different than, say, Facebook consuming their API. There's never all the data for a user in the store. References are implemented with IDs and these are loaded when required.
You can keep all your logic in redux. Just create actions as usual for user actions and data changes, get the data you need and process it. The interface is still completely defined by the user data because you always have the information in the store that is needed to GET TO the rest of it when needed. It's just somewhat condensed, i. e. you only save the total number of messages or the IDs of a mailbox until the user navigates to it.

Non-Transactional SaveChanges with Breeze.js

Imagine you have a UI that consists of a list of items, each with a checkbox beside them. You can select multiple checkboxes and click a button to perform a bulk operation. The desire is to have as many of the rows be processed as possible. So if one row fails, the other selected rows should not roll back.
To do this with Breeze, would it make more sense to send multiple different saves, or is there a way to handle this scenario out of the box?
Sorry. I am new to Breeze, and have been looking through the docs, samples, and API and can't see any clear indication that this is possible. It appears that each call to SaveChanges is transactional. Or is a Named Save required to achieve this behavior?
Thanks in advance!
There is no simple way to do a non-transactional batch save in Breeze. You're easiest course is to save each change individually. You can fire them off in parallel and wait for all to complete if that's important to you.
However, if you're game for some serious programming, it can be done. Here is the outline of the approach.
How to write a non-transactional batch save in Breeze
The easy part is turning off the transaction on the server.
Take a look at the second parameter of ContextProvider.SaveChanges. It's a Breeze TransactionSettings object. If you "new" that up you'll get this
public TransactionSettings()
{
this.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
this.Timeout = TransactionManager.DefaultTimeout;
this.TransactionType = TransactionType.None;
}
You can change create one with any value you like but I'm calling attention to TransactionType.None.
Pass that in your call to SaveChanges
[HttpPost]
public SaveResult SaveChanges(JObject saveBundle)
{
return _contextProvider.SaveChanges(saveBundle, myTransactionSettings);
}
I believe that will prevent the EFContextProvider from saving transactionally.
Now you have to fix things on the client side. I haven't turned off transactions so I'm not familiar with how errors are caught and transmitted to the client.
The real challenge is on the client. You have to do something when the save fails partially. You have to help the Breeze EntityManager figure out which entities succeeded and which failed and process them appropriately ... or your entity cache will become unstable.
You will have to write a custom Data Service Adapter with some very tricky save processing logic. That is not easy!
I've done it in my Breeze Labs Abstract Rest Adapter which is not documented and quite complex. You're welcome to read it and apply its reasoning to your own implementation of the "web api" Data Service Adapter. If you have budget, you might engage IdeaBlade professional services (makers of Breeze)

dojo.store.Observable, JSON REST and queryEngine

Does anybody know how to use the JsonRest store in dojo witn an Observable weapper, like the one in dojo.store.Observable?
What do I need, server side, to implement the store and make it work as an Observable one? What about the client side?
The documentation says http://dojotoolkit.org/reference-guide/1.7/dojo/store/Observable.html
If you are using a server side store like the JsonRest store, you will need to provide a queryEngine in order for the update objects to be properly included or excluded from queries. If a queryEngine is not available, observe listener will be called with an undefined index.
But, I have no idea what they mean. I have never created a store myself, and am not 100% familiar with queryEngine (to be honest, I find it a little confusing). Why is queryEngine needed? What does the doc mean by "undefined index"? And how do you write a queryEngine for a JsonRest store? Shouldn't I use some kind of web socket for an observable REST store, since other users might change the data as well?
Confused!
I realize this quesiton is a bit old, but here's some info for future reference. Since this is a multi-part question, I'll break it down into separate pieces:
1) Server-side Implementation of JsonRest
There's a pretty decent write up on implementing the server side of JsonRest Store. It shows exactly what headers JsonRest will generate and what content will be included in the rest. It helps form a mental model of how the JsonRest api is converted into HTTP.
2) Query Engine
Earlier in the same page, how query() works client side is explained. Basically, the query() function needs to be able to receive an object literal (ex: {title:'Learning Dojo',categoryid:5}) and return the objects in the store that match those conditions. "In the store" meaning already loaded into memory on the client, not on the server.
Depending on what you're trying to do, there's probably no need to write your own queryEngine anyway -- just use the built-in SimpleQueryEngine if you're building your own custom store. The engine just needs to be handed an object literal and it adds the whole dojo query() api for you.
3) Observables
My understanding is that the Observables monitor client side changes in the collection of objects (ex: adding or removing a result) or even within a specific object (ex: post 5 has changed title). It does NOT monitor changes that happen server-side. It simply provides a mechanism to notify other aspects of the client-side app that data changed so that all aspects of the page stay synchronized.
There's a whole write up on using Observables under the headings 'Collection Data Binding' and 'Object Data Binding: dojo/Stateful'.
4) Concurrency
There's two things you'd want to do in order to keep your client side data synchronized with the server side data: a) polling for changes from other users on the server, b) using transactions to send data to the server.
a) To poll for changes to the data, you'd want to have your object store track the active query in a variable. Then, use setTimeout() or setInterval() to run the query in the background again every so often. Make sure that widgets or other aspects of your application use Observables to monitor changes in the query result set(s) they depend on. That way, changes on the server by other users would automatically be reflected throughout your application.
b) Use transactions to combine actions that must be combined. Then, make sure the server sends back HTTP 200 Status codes (meaning 'It Worked!'). If the transactions returns a HTTP status in the 400s, then it didn't work for some reason, and you need to requery the data because something changed on the backend. For example, the record you want to update was deleted, so you can't update it. There's a write up on transactions as well under the heading 'Transactional'

Categories