I have a webservice with a mobile application. The user, with the application shares the data on the server - have a constraint in the DB that the name of the shared object is unique per user. Also application stores locally all created data (by the user - that is also shared).
I have the following scenario:
User creates data with data-name X.
User shares this data.
Server has in it DB data-name X for this user
User has a new phone and install the application.
NO INTERNET CONNECTION
user creates again data with data-name X.
it is stored only locally - since NO INTERNET CONNECTION.
Internet connection restored.
Now a BG service run and start sharing all u shared data - in the BG.
The problem found because of the constraint.
What should be done to solve the problem? I can popup a new window saying that it already shared and ask the user to rename/overwrite it, give option to D/L this data to its local DB etc. But since it is done in the BG - is it user-friendly to show this popup?
Any other ideas?
Probably there is a common way of doing it.
I can really use some help reagrding this issue.
Here is how a recent app I've done handles this:
A user creates a new record on the mobile device. The new record gets assigned a negative primary key _id number.
The app checks for internet connection and, if a connection exists, the app does an HTTP post to the server, creating the record on the server side. The server then sends back a response creating the new PK _id which gets updated in the app.
If no internet connection, the app creates a record in my db_changes table containing the table name and the PK _id of the new record.
A service runs in 5 minute increments which gets updates from the server and posts new data to the server. The db_changes table is polled each time for any existing inserts or updates that yet to be posted to the server.
Once successful, the record from the db_changes table gets deleted.
In my situation, this works perfectly.
for this, you generally don't use a name or something of that sort, but UUIDs - i.e. 32-to-64 character long random strings that uniquely identify an object. When you create an object, just create a UUID on the device and sync this to the server. Heres the documentation of the UUID class in android.
While it theoretically feasible to have the same UUIDs, it's something you generally don't worry too much about it, as stated here: http://en.wikipedia.org/wiki/Universally_unique_identifier#Random_UUID_probability_of_duplicates
For iOS, you can use the CFUUID class to generate UUID
Another name for UUIDs ist GUID, Globaly unique identifiers. Hence, you remove any kind of uniqueness constraint.
Related
We have a mobile application. There is a sales module. It calls the sales rest api to create a sales order.
Format of the sales api POST request:
//server generates primary key. there is no support for request id currently
{
"customer_id" : 1,
"items" : [
{ "item_id" : 123 },
{ "item_id" : 456}
],
"store_id" : 10,
"sale_time" : "2019-10-01 13:45:01"
}
As we have to support offline mode, all sales will be stored locally on the device and when the internet connection is available it will sync with the server.
But I got to know that http libraries can retry http request multiple times if the internet connectivity is poor. But this may cause to create multiple sales entry on the server.
How to implement syncing offline data properly given that server(rest api) generates the primary key for the new record? Updating existing record is fine as it has primary key generated by server but how to deal with new records without a primary key?
Scenario:
App is in offline mode
User creates a sales order and saves it locally
After sometime, say there is limited internet connectivity.
App fetches all yet to be synced records and calls rest API for each one.
Sales Rest API called for 1st record and app is waiting for response.
Internet connection fails, but server creates record and fails to notify the app
After few minutes say Internet connection is back, now app tries to call sales api for the 1st record again and receives success response as well. But there are two entries in the server.
How to fix this?
2 ways to handle this
1)using sync-status
when you store the data in storage add one more flag as "sync-status" and the data type will be boolean default is false. and get only those data that have sync-status as false. if data successfully sends to server change status as true.
2)sever syn-date-time
if your server send you sync date-time then this will be possible, you need to check the date after server-sync-date-time that data only u need to sync with the server
This is a tricky scenario. If you are having to deal with a single client communicating with an API, then simply passing a unique identifier to the API from the client and storing it, checking it before creating any future records will do the trick, as mentioned by Md. Asaduzzaman.
However, in a scenario where you have many clients using the same API, I would further extend this to include user information, so you know what client this request has come from. This is to avoid overlapping identifiers between clients. Yes GUIDs are unlikely to overlap, but it is possible.
This is cool, for creating new records for example, but what about updating existing records? In this case, you would also need something like a lastModifiedTime field both on the client and API, if the API lastModifiedTime is ahead of the client, then you have a conflict that needs to be dealt with.
You could perhaps have a single table in the API which is called EntitySyncStatus consisting of EntityTypeId, EntityId, ClientEntityId, UserId(or DeviceId), and lastModifiedTime could either be maintained in this table, or in the entity table.
This model will then support syncing multiple objects, without storing sync related fields on each individual entity, but also provide more flexibility and visibility.
I have an SQLite database on Android and a MySQL database on a server. I want to synchronize these databases when a user edits data on their phone or edits data on a website.
I know how to update the MySQL database on the server when a user makes changes on their phone but I don't know how to update the Android database when a user makes changes on the website.
I have read into push notification and believe this to be a good path to follow but I have a few questions about it:
When a user updates data through a website it will send a push notification to that user's phone saying changes have been made. Can this push notification trigger to update the Android's database with the new changes made on the Server database?
What if a user turns off push notifications? Will I still be able to trigger for their Android database to be updated?
I have also read up on SQLite and MySQL database synchronization and found this post SQLite and MySQL sync but did not find the post helpful for my situation.
Are push notifications a good way to go or should I be using a different approach?
In a nutshell - I want a way for the Android device to detect changes on the MySQL database and update its SQLite database without the user initiating the synchronization.
I'm afraid I've not used push notifications. But a solution might be: You could create an early method call to an Asynchronous polling event from the launcher onCreate() that looks up the server to see if any changes have been registered (though an API of some sort) in the MySQL, and then update the SQLite that way? Since it's the first thing that happens on launch, technically the user isn't initiating it. Granted this won't update during use of the app, unless you repeat poll at regular intervals?
Token based pagination approach.
Assumptions: or calls you need to take
One of the databases will the source of truth, in case of differences in the two, which data is true, and which will be overwritten? - assuming remote database is source of truth
What's the frequency of data changes? - assuming its not realtime critical
How much stale data are we OK with dealing on the app. - assuming we're OK with a few minutes of difference
How to ensure data is consistent
Find a method to associate a token, which can be used to identify till which record is the data in sync. This is important no matter how assured you are of web requests, they will fail. So the best method is to send the last token that have stored, and the web endpoint will return data from that token to the latest value.
If the volume of data is too much here, sending chunks > sending all of it. Chunks work the same way, based on tokens.
These tokens can be simple PK auto increment column as well.
How to deal with time difference, stale data
If your application demands some data to be near realtime, better to categorize data based on a fiew screens, and whenever the user comes to the said screen, send a request in background to fetch related data columns only. Will ensure the data stays in sync w.r.t to the important columns. This is a classic push/pull approach. Can also be done on the splash screen itself.
as a rule of thumb, if you need something urgent, pull.
if it can wait, wait for a push.
Push notifications are OK as far as:
they should be silent.
there'a a limit on the number of push notifications that you can send
have costs associated
what's the fail - check mechanism? What if the requests fail?
I have been trying to implement SyncAdapter to sync data between client(android device) and server using sqlite.The same data will be shared between different devices.
On Update:
As soon as a particular record is updated on one client device it will be pushed to the server. At that moment the updated record should also be synced from the server to other connected devices.
Now, when we send sync request from other connected devices, what is the best way to know which record get updated on the server?
Here is what I would do to achieve this:
First, consider using timestamps. Here is how that could work;
In your database table (remotely), have a column updated_at which as soon as you sync your fresh data up, you should set a new timestamp for it.
In your android code, you can simply store lastSyncTime in your preferences then compare with what you get from your server column.
You can easily pull the value from an endpoint /last_sync/ to see if the sync_time has changed.
By comparing the two timestamps, you can then decide as to whether you want to sync down new data or keep the old until the new ones are synced.
I hope this helps. Good luck!
These days i am working on an Android Application and i have problem with data synchronization.
I am using JSON for transferring data.
Now i'll explain my problem.
Assume that you have one server and multiple Android devices which is sending data between each other. We have same database tables not only on android devices but also server.
Operation of system is like this :
At the beginning of day, Android devices must receive data from server.
During day, Android devices can change data in own database but it won't change data on server database.
At the end of day, Android devices will send
inserted,
updated,
deleted data to server.
My problem is starting here..
My code is logging every changes in Android device for sending at the and of day to server.
User A is added this data during day (id=1024 name=testA value=testAvalue)
User B is added this data during day (id=1024 name=testB value=testBvalue)
And then user B wanted to change data name during day (id=1024 name=testC value=testBvalue)
At the and of day, Firstly user A sent data to server. Now server has this data
(id=1024 name=testA value=testAvalue)
Secondly, user B sent data to server. Create(id=1024 name=testB value=testBvalue)
Here this data id will not be 1024 because server database has data which id is 1024. New data id will be 1025.
Now server has 2 data
(id=1024 name=testA value=testAvalue)
*(id=1025 name=testB value=testBvalue)*
And then, server will receive edit command like this
Edit(id=1024 name=testC value=testCvalue)
It will edit 1024. data and it will be wrong
(id=1024 name=testC value=testCvalue)
(id=1025 name=testB value=testBvalue)
This is a typical "he who saves last wins" problem. You have copies of the data out in the field, and you need to aggregate and synchronize updates at the end of the day. The problem here is not so much technical as it is a problem of design:
"How can I accept batched data updates from multiple sources when the updates conflict?"
So, this is really a conflict resolution problem. The "right" solution will depend on your application requirements.
One solution is to assign "ownership" of records to a device, so that only that device can make an update. An example might be a sales force in which representatives are assigned clients. Only the rep assigned to a client can make changes to records associated with that client.
Another solution is to write specific rules for resolving conflicts into the system. Your specific business case will determine exactly how to resolve each conflict. As long as your application cannot make changes to the server in realtime, this is probably your best bet to accept updates to the same record from multiple sources.
One of your problem is in ID collision. You need to select the appropriate column types for your primary keys based on your specific requirements.
Let me suggest few options (they all have some advantages and disadvantages).
Auto-Increment (Identity) columns: the clients only create temporary ids and replace with permanent ones after the server creates new records and send the newly generated ids to the clients.
Or the server will designate the range of ids for each client. E.g. Client A will insert records from 1-100000, Client B: 100001-200000, etc. Once new records riches the range limit the server should issue the new range.
GUIDs: each client will generate unique id on insert using new UUID() command and then your server will be able to insert or update the client changes without any problems.
I am working on a Point of Sale application that needs to be very good syncing mechanism. We have Magento Database.The android device have SQLite local Db. Now we need to sync in the following way:
Local ------Sync To---------------> Server (Up Sync)
Server------Sync To---------------> Locals (Down Sync)
There are 2 things:
1) write-to (How to take care??)
For every change that i do on local ,it will directly sync my local to server
2) write-back (How to take care???)
Whenever there is a change in server, we need to sync all our locals with server.
So, the task is: to identify a server update
And sync our locals.
Like there are 4 devices are running in a store and we have added one new customer through one device. Now i want that the three other devices local db also updated with the information about that customer and server also updated.
I heard about the background threads and run threads after a time interval. But what is the best way to do that which don't affect the application. Also the all Big Retail stores uses the syncing process. what they used for that ?
Any help is appreciated.
It fully depends on you database structure...
you have DATABASE in LOCAL (device) and on SERVER
NOW
You need to have TIMESTAMP fieLd added to the TABLES which actually you want to keep in SYNC.
When ever you will make any changes on server the TIMESTAMP will be updated there and same will be the case for the local database also what you have to do is now.
Run a service in the background which will keep on comparing the TIMESTAMPS of LOCAL with that of SERVER.
Now you have to put condition that if TIMESTAMP of SERVER is newer to that of LOCAL then bring changes from SERVER to LOCAL,
and vice versa will be the condition to take changes from LOCAL to SERVER.
Further you have to decide how frequently you want to run this SERVICE.
ALTERNATIVELY:
You can make the table there on SERVER which will store LAST_SYNCHED date for particular device
Whenever you will login in you device (or any other particular event on which you want it to perform this) the server will check-
when this device was LAST_SYNCHED
then it will compare it to TODAYS DATE
and will check what upadets actualy happened between these dates and
will send the changes to the LOCAL (device)
and vice versa for LOCAL (device) to SERVER
you have to play with TIMESTAMPS rest you can have your own logic how to structure the database.
I told you what I have have observed, when I have been a part of such similar project
EDIT
The above Process defines how to sync the devices with server I mean the strategy..
If you want your devices to get notified from server when to sync instead of hitting the WEB-SERVICE recurrently ..
You can make use of PUSH NOtification, GCM is one of them that send push notification to devices, you can integrate it to your project
For syncing you need to handle following two situations.
How and when to receive server updates
How to identify local non-synced data
How and when to receive server updates:
For receiving updates, we can use GCM (Google Cloud Messaging). If any updates made in server, server sends a push message to all devices. Devices will receive that push and based on the message, devices will download the data from server. (I think this is better approach than continuous hitting service for some particular intervals like polling)
For receiving only updated data from server, server maintains modified_timestamp column for all tables. First time devices will send empty timestamp, so that server sends all data to the device with server timestamp. Device receives the new data and updates local db and saves the latest server timestamp. For next time to get server updates, device will send stored server timestamp then server will send only modified data after that timestamp only. For each response server sends server timestamp, devices needs to store that timestamp and needs to use while calling service.
How to identify local non-synced data:
For sending local updates, local db needs to maintain one 'isSynced' column in tables. If any row modified in local isSynced will be false, after successful syncing local data to server isSynced will be true. so that we can handle local data up to date with server.
Updated:
You can find more information on this developer link
Have you considered using commercial solution?
http://www.mobeelizer.com/ seems like what you want to achieve. There are probably many other.
Note: no affiliation with that company.
I would say that the problem statement is incomplete. In above described setup what is missing is what actually you are going to synchronise.
Usual case in POS is that there exist few indices (id,value,...) tables that shall be distributed from central server to the client devices. In most cases it is price list, stock list, etc. Those tables should rarely be modified on client devices (actually could but then has to be redistributed from central server and acknowledged by client devices).
The other direction tend to be also pretty straightforward on client device you generate bills or invoices. These are again local stuff that shall be propagated towards server. Thus you actually store them locally and at sync point dispatch them to the server. Later on you might receive your own items back from server as an acknowledge.
EDIT: to detect changes, on-write timestamps as mentioned above is a must.
So far above described is the data flow.
Next you have to move into solution domain and implement these rules. There is couple of sync approaches (i.e.SyncML). On the other hand keeping it simple rulez. Thus the main concern should be some kind of locking and queueing that makes the thing robust.
It could also use the agent based client, in such case each device has it own agent (could be replica of last known state of the device db) but I would consider this as an advanced feature that might come in future release:-)
I am also working on the sales app in which i have to my local goals to server and server goals to my local goals
My proceder is that when ever my app is started i get the latest data from my server of my all my member and update my local data base with this data and when ever i change data in my local data base also update on sever side
also i used a sync button which will fetch latest data from the server if my team member changes its goal or profile
IF you want updated data on all the devices, why don't you use remote database only, why are you introducing local database for this.
For your case i will suggest you to work with only remote database directly so the things can be done real time.