BreezeJs: SaveChanges() server response getting dropped - javascript

I have breezeJs running in an angular app on mobile device (cordova), which talks to .Net WebApi.
Everything works great, except once in a while the device will get PrimaryKey violations (from my SQL Server).
I think I narrowed it down to only happening when data connection is shakey on the device.
The only way I can figure these primary key violations are happening is somehow the server is Saving Changes, but the mobile connection drops out before the response can come back from server that everything saved OK.
What is supposed to happen when BreezeJS doesn't hear back from server after calling SaveChanges?
Anyone familiar with BreezeJS know of a way to handle this scenario?

I've had to handle the same scenario in my project. The approach I took was two part:
Add automatic retries to failed ajax requests. I'm using breeze with jQuery, so I googled "jQuery retry ajax". There's many different implementations, mine is somewhat custom, all center around hijacking the onerror callback as well as the deferred's fail handler to inject retry logic. I'm sure Angular will have similar means of retrying dropped requests.
In the saveChanges fail handler, add logic like this:
...
function isConcurrencyException(reason: any) {
return reason && reason.message && /Store update, insert, or delete statement affected an unexpected number of rows/.test(reason.message);
}
function isConnectionFailure(reason: any): boolean {
return reason && reason.hasOwnProperty('status') && reason.status === 0
}
entityManager.saveChanges()
.then(... yay ...)
.fail(function(reason) {
if (isConnectionFailure(reason)) {
// retry attempts failed to reach server.
// notify user and save to local storage....
return;
}
if (isConcurrencyException(reason)) {
// EF is not letting me save the entities again because my previous save (or another user's save) moved the concurrency stamps on the record. There's also the possibility that a record I'm try to save was deleted by another user.
// recover... in my case I kept it simple and simply attempt to reload the entity. If nothing is returned I know the entity was deleted. Otherwise I now have the latest version. In either case a message is shown to the user.
return;
}
if (reason.entityErrors) {
// We have an "entityErrors" property... this means the saved failed due to server-side validation errors.
// do whatever you do to handle validation errors...
return;
}
// an unexpected exception. let it bubble up.
throw reason;
})
.done(); // terminate the promise chain (may not be an equivalent in Angular, not sure).
One of the ways you can test spotty connections is to use Fiddler's AutoResponder tab. Set up a *.drop rule with a regex that matches your breeze route and check the "Enable Automatic Responses" box when you want to simulate dropped requests.
This is a somewhat messy problem to solve- no one size fits all answer, hope this helps.
NOTE
Ward makes a good point in the comments below. This approach is not suitable in situations where the entity's primary key is generated on the server (which would be the case if your db uses identity columns for PKs) because the retry logic could cause duplicate inserts.

Related

Which event is triggered when we use ref.push to write in firebase database javascript

When we are working in firebase using javascript which event is triggered after we insert data using ref.push or ref.set.
I wanted to know if my data is inserted or not
I also wanted to throw an error when user have disconnected from internet while inserting data in firebase
I haven't seen any function or any method in internet which tells me about if data is successfully inserted or not.
This functions Promise-based, so you can use try/catch:
try {
firebase.push(data) // or set
} catch (error) {
console.log(error) // here is error
}
The Firebase Realtime Database doesn't consider a lack of internet connection an error condition. Instead it continues to work to its best ability in the given conditions.
When you perform a write operation (with set, push, update, or remove) while there is no internet connectivity:
The first client fires local events immediately, so that your app can update the UI for the new/updated data.
It then queues the write operation for delivery once the connection is restored.
Once the connection is restored, the client sends any pending write operations it has in the order in which the client performed them.
It then handles the response from the server, which (if the server rejects the operation because of security rules) may lead to firing more local events so that the app can put the UI back into the correct sate.
And it then finally calls any completion listeners, and resolves or rejects the promise for the set(), push(), update(), or remove() method.
You'll note that there is no error raised at any point for a lack of an internet connection.
If you don't want to send any data to the local queue when the app has no internet connection, it's best to detect if the Firebase client is connected to the server. You can do this by listening to the .info/connected pseudo-node. This covers more than just having an internet connection btw, but also cases where the internet connections works but the client can't reach Firebase. The best practice here is to use a "global" listener for this status, and disable the relevant UI elements if the client is not connected.

Is it possible to get request information from a rxjs-timeout-error?

I'm trying to improve our current implementation of error handling and one part of it is the better description of errors in general and also in testing environments. I do this for an Ionic app but since my problem lies within the rxjs timeout-method, I think this is neglectable.
One part im currently stuck on is the correct visualization (error message) of timeout errors since they don't seem to contain anything of value at all. I'd like to show to the user which request was the origin of the timeout error when the error happens and the user sees. In the case of testing environments additional thinks like url, device-version, etc. should be shown as well.
But all the Timeout-Error contains seems to be a stacktrace of the javascript library beneath handling the post request.
So, my question is if there is a way to add or retrieve additional information from an rxjs timeout error?
Below you can see how the TimeoutError from rxjs looks for me.
Thanks!
TimeoutError has nothing to do with values emitted by the source Observable. Still, it's thrown when there are no emissions from the source so what how could it contain any information anyway.
What you can do however is use catchError to get the error that produced, turn it into another error and send it further with throwError:
...
catchError(e => throwError({...e, ...whatever}))
You can for example check whether the error is an instance of TimeoutError and if it is the do something with it.

Is data cached on server or client or not at all in AngularJS when an error occurs in a promise?

Keep in mind, I'm running an old version of AngularJS (1.0?), so things may have changed, but I have code that looks like:
promise = $http.get(urlFormattedString).success(function (data) {
data.forEach(function (result) {
//do something with result and $scope});
promises.push(promise);
$q.all(promises).then(function (data) {
//do something good when everything works!
};
When no errors are thrown, everything "works", but my question is what happens when one of the promises throws an error (say 1 out of 20)? Let's make this more interesting (and closer to my application) and assume that each promise is requesting data from a database (MongoDB in my case).
If I have to re-run everything, does that mean necessarily that all the data needs to be fetched again? Am I relying on the database to cache the data so the repeated requests run much faster? Or maybe the server (NodeJS in my case) caches the data? Along these lines, when are the data actually sent to the client from the server? Is it only upon success of all promises or is the data returned to the client from each promise separately? And if so, does Angular do the caching?
Just laying this out here makes me realize this is pretty complex and lots of scenarios to consider. Would appreciate any help or pointers to reading/documentation on this subject. Thanks!
Suggest you familiarize yourself with the network tab of your browser dev tools.
You can see every request made for all resources from html to images to scripts as well as ajax requests. This will give you a far better feel for how the app works in general
As for errors ... unless you implement error handling your app will simply fail for that request with no indication given to user that anything went wrong.
As for caching ... your ajax requests won't be cached client side and unless you have implemented caching mechaanisms on server they won't be cached there either

Unhandled Exception: System.TimeoutException: The request channel timed out while waiting for a reply after 00:01:59.4579323

i am new to crm2011
i tried creating a plugin and then registering it with the Plugin Registration tool
here is the code for Plugin.cs file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using Microsoft.Xrm.Sdk;
using Xrm;
using System.Runtime.Serialization;
namespace NewPlugin
{
public class Plugin : IPlugin
{
/// <summary>
/// A plugin that creates a follow-up task activity when a new account is created.
/// </summary>
/// <remarks>Register this plug-in on the Create message, account entity,
/// and asynchronous mode.
/// </remarks>
public void Execute(IServiceProvider serviceProvider)
{
//Extract the tracing service for use in debugging sandboxed plug-ins.
ITracingService tracingService =
(ITracingService)serviceProvider.GetService(typeof(ITracingService));
// Obtain the execution context from the service provider.
IPluginExecutionContext context = (IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));
// The InputParameters collection contains all the data passed in the message request.
if (context.InputParameters.Contains("Target") &&
context.InputParameters["Target"] is Entity)
{
// Obtain the target entity from the input parameters.
Entity entity = (Entity)context.InputParameters["Target"];
throw new InvalidPluginExecutionException("Plugin could not be registered");
}
} }
}
}
but While i register this plugin i get the below error
Unhandled Exception: System.TimeoutException: The request channel timed out while waiting for a reply after 00:01:59.4579323. Increase the timeout value passed to the call to Request or increase the SendTimeout value on the Binding. The time allotted to this operation may have been a portion of a longer timeout.
Server stack trace:
at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.SecurityChannelFactory`1.SecurityRequestChannel.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
Exception rethrown at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at Microsoft.Xrm.Sdk.IOrganizationService.Create(Entity entity)
at Microsoft.Xrm.Sdk.Client.OrganizationServiceProxy.CreateCore(Entity entity)
at Microsoft.Crm.Tools.PluginRegistration.RegistrationHelper.RegisterAssembly(CrmOrganization org, String pathToAssembly, CrmPluginAssembly assembly)
at Microsoft.Crm.Tools.PluginRegistration.PluginRegistrationForm.btnRegister_Click(Object sender, EventArgs e)
Inner Exception: System.TimeoutException: The HTTP request to 'https://demoorg172.api.crm.dynamics.com/XRMServices/2011/Organization.svc' has exceeded the allotted timeout of 00:01:59.9970000. The time allotted to this operation may have been a portion of a longer timeout.
at System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason)
at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
Inner Exception: System.Net.WebException: The operation has timed out
at System.Net.HttpWebRequest.GetResponse()
at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
Please help me if u can solve this.
Here this will help anyone struggling with this: Check this website out: azure preconfiguured it's ready to be compiled and has a one click method and is already on azure. My second guess was correct you didn't have all the appropriate ports and firewall off and buying a certificate and a domain...... So just check that out and compile it real simple. I don't like crm2011 but I know way more about it now than I did. I didn't know I could do ajax and javascript and pretty much anything thru iframe. Cheers hope this makes things easier.
Nice so you are fairly new to crm and cs scripts for Iplugins? The SDK is great, more than enough.
Your lines look fairly tight but I see a few lines that need a little scrubbing. I don't spend very much time with crm but I do have a little knowledge in it due to the fact that a plugin is just and executable script, so very similar to JavaScript, Ajax, python, html....
It look's like to me when you are using the argument // Obtain the execution context from the service provider.
IPluginExecutionContext context = (IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));
// The InputParameters collection contains all the data passed in the message request.
if (context.InputParameters.Contains("Target") &&
context.InputParameters["Target"] is Entity)
{
// Obtain the target entity from the input parameters.
Entity entity = (Entity)context.InputParameters["Target"];
///Everything looks perfect up to that point but the service providers all have time
exceptions or if, they just don't like you pulling off of them if you don't have super
clean code. It will throw a fit and knock you off every time within probably a little over
a minute. When you are trying to pull the context params off you need to let it know what
you are doing with a so before this line of code you are going to need to put in a time
exception argument which allocates you time.
///I don't know what exactly your target is but it is a domain correct?
If so you just need to throw an exception at it that will allow you
to register and stay there all damn day if you please.
///when it throws this "System.TimeoutException" it then proceeds to give you a miniscule
amount of time to respond because it is a script so it can execute however fast the ping is.
Right before you request anything use this exception
//<serviceProvider.TimeoutException="Target"></client>
///if it wants to keep being stubborn than continue to clean up your lines and use the
/></system argument whenever it throws a fit about time. reminds me a lot of old
school html and python.
/// If you are actually going one on one with the server you can throw a
//<serviceProvider or
<domain.GetService.TimeoutException="reqast_info">*</client>
///That should allow it to continue without losing any packets or throwing
any "time" exception
///Ipv6 Protocols work really well. Also Open ports on the domain tcp and udp and sock 4
and 5 then the highest volume consumed ports the
port 80 and 25...... well Lets just say it is the most forgiving port and easiest going
there is.
///I hope I wasn't to late , but if I was than I am happy you got that "HelloWorld.cs"
Registered. Anyways man hope all is well. Sorry If I am not a huge help because I have,
probably sounds and looks just like JavaScript.
///When I was reading the handler exception, I noticed a portion that was talking about a "Boolean"
This can be significant because it can really throttle any incoming data down to a crippling demoralizing fail every time. Just like a full blown firewall except there are no exceptions.
"String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs"
The Boolean works as a packet filter. And it's not set for in and out traffic. So it can push a ton of packets but it just receives enough to be able to do it's job. I remember proxy servers... real proxy servers at school called mcproserver port 8080, tunneling and very aggressive." And proxy servers also slow way down the more traffic they are throwing around.
Do a little investigative work on that domain and get their ipv6 address and run some net challenges thru the terminal so you can find out exact what the limits are on the other-side, im going to say it clears logs and dynamically drops the proxy one of several hundred they rotate; every two hours, if you weren't tunneling thru to it via a client than it would kick you off in exactly 2 seconds. They server itself probably resets itself once ever 7 days. It's most likely an A+AAAA class and ridiculous. That Boolean also caps the bandwidth at which the proxy server can down-link complex packets.
First off you have to have a secure registered account or it will never go anywhere and second the domain:'https://demoorg172.api.crm.dynamics.com/XRMServices/2011/Organization.svc' doesn't even exist as a domain at all so that could be your whole issue because it is failing to establish a connection for two hours. There is no way. Your lines are great very simply. Shit better than me. and I can't get to any portion of that domain by either pinging it or nslookup
So It looks like to me you will have to first establish a secure connection via client I assume or if you know the port and you have authorization than you can run some tests on the server so you can not just continue to waste your time just to find out it cannot establish a http connection with it.
Your plugin has nothing to do with it. You aren't establishing a proper connection with the domain therefore probably losing 90 percent of packets or just shuts you down from the get go but will wait two hours if you are using terminal start the net share or send and tunnel in with elevated privileges then login instead of using a webrowser or client. Then once if you can establish a conection with the domain and it's not dropping packets and if it exists than you are golden.
But either you need to open a few ports on your end and open your nat and make a firewall exception or it is on there end. Most likely the former. You can still try adding the lines I slopped up for you which do allocate more time. But now that I got farther into it. It took your plugin fine cooked it and then synched up and then down towards the very bottom after it's done doing everything it throws a 0 and shuts you down. I am sure I just wasted my time typing this because I just realized it was asked 3 months ago. Hope you are excelling in your abilities by this time.
P.s. before I forget, the Timeout could be a Buffer Overflow a very small one that kicks you off while you are trying to register. But I guarantee that there is only an astronomical chance that it would execute and trip whatever you are pulling the target off. If it is anything like python then you can slightly alter the lines I typed with to make them "div" extension and just an easier way to go in my personal experience:
<div class="row-fluid">
</div>
<div class="row-fluid">
<div class="span6">
<label>
<input type="text" name=name of the domain that you are using."
<span class="inline_error_message error_"></span>
</div>
<div class="span6">
<input type="text" name="" value= />
<span class="inline_error_message error_">_</span>
</div>
<div class="row-fluid">
///These are java script row-fluid
///I doubt those will help
Does this fix it? I'm about to try it...
http://social.microsoft.com/Forums/en-US/8b408943-45cc-4104-b3f8-5f926312c7bc/crm-2011-plugin-registration-tool-timeout-error?forum=crmdevelopment

Accessing IndexedDB from multiple javascript threads

Overview:
I am trying to avoid a race condition with accessing an IndexedDB from both a webpage and a web-worker.
Setup:
Webpage that is saving items to the local IndexedDB as the user works with the site. Whenever a user saves data to the local DB the record is marked as "Unsent".
Web-worker background thread that is pulling data from the IndexedDB, sending it to the server and once the server receives it, marking the data in the IndexedDB as "Sent".
Problem:
Since access to the IndexedDB is asynchronous, I can not be guaranteed that the user won't update a record at the same time the web-worker is sending it to the server. The timeline is shown below:
Web-worker gets data from DB and sends it to the server
While the transfer is happening, the user updates the data saving it to the DB.
The web-worker gets the response from the server and then updates the DB to "Sent"
There is now data in DB that hasn't been sent to the server but marked as "Sent"
Failed Solution:
After getting the response from the server, I can recheck to row to see if anything has been changed. However I am still left with a small window where data can be written to the DB and it will never be sent to the server.
Example:
After server says data is saved, then:
IndexedDB.HasDataChanged(
function(changed) {
// Since this is async, this changed boolean could be lying.
// The data might have been updated after I checked and before I was called.
if (!changed){
IndexedDB.UpdateToSent() }
});
Other notes:
There is a sync api according to the W3 spec, but no one has implemented it yet so it can not be used (http://www.w3.org/TR/IndexedDB/#sync-database). The sync api was designed to be used by web-workers, to avoid this exact situation I would assume.
Any thoughts on this would be greatly appreciated. Have been working on it for about a week and haven't been able to come up with anything that will work.
I think I found a work around for this for now. Not really as clean as I would like, but it seems to be thread safe.
I start by storing the datetime into a LastEdit field, whenever I update the data.
From the web-worker, I am posting a message to the browser.
self.postMessage('UpdateDataSent#' + data.ID + '#' + data.LastEdit);
Then in the browser I am updating my sent flag, as long as the last edit date hasn't changed.
// Get the data from the DB in a transaction
if (data.LastEdit == lastEdit)
{
data.Sent = true;
var saveStore = trans.objectStore("Data");
var saveRequest = saveStore.put(data);
console.log('Data updated to Sent');
}
Since this is all done in a transaction in the browser side, it seems to work fine. Once the browsers support the Sync API I can throw it all away anyway.
Can you use a transaction?
https://developer.mozilla.org/en/IndexedDB/IDBTransaction
Old thread but the use of a transaction would solve the Failed Solution approach. I.e. the transaction only needs to span the check that the data in the IndexedDB hasn't change after the send and marking it as sent if there was no change. If there was a change, the transaction ends without writing.

Categories

Resources