ApacheIgnite stability with WebAPI 2 - iis

I have a setup that runs ApacheIgnite 2.7.6 on multiple WebAPI services. I instantiate IIGnite within the Global.asax Application_Start method for each WebAPI service. Then within my controllers I access the cache from a public DataCache property in the WebApplication class. The services call each other and Ignite makes a common cache for all services. Now, when running unit tests continuously Ignite becomes unstable. The timing is random, sometimes 30 minutes, sometimes 20 hours. Looking for tips to make my code stable or tips to on how to recover after instability.
My setup code includes a loop for instantiating the IIgnite and looks something like this:
using Apache.Ignite.Core;
using Apache.Ignite.Core.Cache;
using Apache.Ignite.Core.Resource;
using Apache.Ignite.Linq;
namespace MyService
{
public class WebApiApplication : System.Web.HttpApplication
{
[InstanceResource]
private static IIgnite IgniteEngine; //{ get; set; } = null;
private static Apache.Ignite.Core.Cache.Configuration.QueryEntity queryEntity = new Apache.Ignite.Core.Cache.Configuration.QueryEntity( typeof( Tuple<string, byte> ), typeof( SomeClass ) );
public static ICache<Tuple<string, byte>, SomeClass> DataCache => IgniteEngine.GetOrCreateCache<Tuple<string, byte>, SomeClass>( new Apache.Ignite.Core.Cache.Configuration.CacheConfiguration( nameof( DataCache ), queryEntity ) );
protected void Application_Start( object sender, EventArgs e )
{
GlobalConfiguration.Configure(WebApiConfig.Register);
InitializeCache();
}
protected void Application_End( object sender, EventArgs e ){}
public static void InitializeCache()
{
try
{
short startCounter = 0;
Stopwatch sw = new Stopwatch();
sw.Start();
//Get the Ignite name - give options for debug environment and production environment
string siteName = System.Web.Hosting.HostingEnvironment.SiteName ?? System.Reflection.Assembly.GetExecutingAssembly()?.GetName()?.Name ?? System.AppDomain.CurrentDomain?.FriendlyName;
#if ( DEBUG || UNIT_TEST )
//Ignite uses H2 Database internally. Cache data is represented as SQL tables based on the CacheConfiguration
//To open H2 debug console and examine the database at runtime, set the IGNITE_H2_DEBUG_CONSOLE environment variable to true before starting Ignite.
//A web browser window will open during Ignite startup and show the state of the H2 database on the current node. Wait for the caches to start and refresh the browser.
Environment.SetEnvironmentVariable( "IGNITE_H2_DEBUG_CONSOLE", "true" );
#endif
//The JVM takes time to start. It could take several minutes when debugging
do
{
startCounter++;
//Sleep a little between tries
#if ( DEBUG || UNIT_TEST )
if ( startCounter >= 1 ) System.Threading.Thread.Sleep( 2000 );
#endif
try
{//Try to get a pre-existing instance of Ignite
IgniteEngine = Ignition.TryGetIgnite( siteName );
if ( null == IgniteEngine )
{
Debug.WriteLine( "InitializeCache attempt {0} to get an existing ignite instance failed.".Format( startCounter ) );
}
else
{
Debug.WriteLine( "InitializeCache attempt {0} to get an existing ignite instance succeeded.".Format( startCounter ) );
}
}
catch ( Exception ex )
{
Debug.WriteLine( "InitializeCache error while trying to get existing ignite instance. {0}".Format( ex.Message ) );
}
if ( null == IgniteEngine )
{
try
{
//Start the engine
string path = System.Web.HttpContext.Current?.Server?.MapPath( #"~\bin\libs" ) ?? System.IO.Path.GetDirectoryName( System.Reflection.Assembly.GetExecutingAssembly().Location ) + #"\libs";
string workPath = #"C:\Dev\Somefolder";
IgniteEngine = Ignition.Start( new IgniteConfiguration
{
JvmClasspath = System.IO.Directory.GetFiles( path ).Aggregate( ( x, y ) => x + ";" + y ),
IgniteInstanceName = siteName,
//Logger = new LogHelperForApacheIgnite(),
WorkDirectory = workPath
} );
if ( null != IgniteEngine )
{
Debug.WriteLine( "InitializeCache success starting Apache Ignite after {0} attempts and {1} seconds".Format( startCounter, sw.Elapsed.TotalSeconds ) );
}
}
catch ( System.BadImageFormatException ex1 )
{
Debug.WriteLine( "InitializeCache failed while trying to start a new ignite instance. The Apache Ignite cache runs as a 64bit dll but an attempt was made to invoke it while running the unit test at 32bits. Fix this from the Test menu by selecting \"Test Settings -> Default Processor Architecture -> x64\". The full error message is: {0}".Format( ex1.Message() ) );
}
catch ( Exception ex2 )
{
if (ex2.InnerException != null && ex2.InnerException.Message.Contains( "ERROR_BAD_EXE_FORMAT" ))
{
Debug.WriteLine( "InitializeCache failed while trying to start a new ignite instance. The Apache Ignite cache runs as a 64bit dll but an attempt was made to invoke it while running the unit test at 32bits. Fix this from the Test menu by selecting \"Test Settings -> Default Processor Architecture -> x64\". The full error message is: {0}".Format( ex2.InnerException?.Message ) );
}
else
{
Debug.WriteLine( "InitializeCache error while trying to start a new Apache Ignite instance. {0}".Format( ex2.Message ) );
}
}
}
}
while ( null == IgniteEngine && sw.Elapsed.TotalMinutes <= 4 );//The JVM sometimes takes more than a minute
sw.Stop();
if ( IgniteEngine == null )
{
string message = "Apache Ignite failed to start. InitializeCache unable to start ignite after {0} tries and {1} seconds".Format( startCounter, sw.Elapsed.TotalSeconds );
Debug.WriteLine( message );
throw new Exception( message );
}
else
{
Debug.WriteLine( "InitializeCache: Ignite running fine. Proceeding to create cached structure(s)." );
}
}
catch ( Exception ex )
{
Debug.WriteLine( "InitializeCache: Exception thrown during Cache initialization {0}".Format( ex.Message ) );
}
}
}
}
I have seen two types of errors once Ignite becomes unstable:
(1)When calling DataCache.ContainsKey( new Tuple( somestring, somebyte ) ) I get:
```BinaryObjectException "Failed to serialize object [typeName=String]"
Failed to serialize object [typeName=String]
EXCEPTION
Failed to serialize object [typeName=String]
at Apache.Ignite.Core.Impl.PlatformJniTarget.InStreamOutLong[TR](Int32 type, Action`1 outAction, Func`3 inAction, Func`2 readErrorAction)
at Apache.Ignite.Core.Impl.PlatformTargetAdapter.DoOutInOpX(Int32 type, Action`1 outAction, Func`2 inErrorAction)
INNER EXCEPTION
{"class org.apache.ignite.binary.BinaryObjectException: Failed to serialize object [typeName=String]\r\n\tat org.apache.ignite.internal.binary.BinaryClassDescriptor.write(BinaryClassDescriptor.java:840)\r\n\```
(2)When calling DataCache.AsCacheQueryable().Where( x => x.Name == "Something" ).SingleOrDefault() or other queries I get
```Java exception occurred [class=java.lang.NullPointerException, message=]
Apache.Ignite.Core.Common.IgniteException, Apache.Ignite.Core, Version=2.7.6.40414, Culture=neutral, PublicKeyToken=a487a7ff0b2aaa4a
java.lang.NullPointerException
at org.apache.ignite.internal.processors.cache.IgniteCacheProxyImpl.getConfiguration(IgniteCacheProxyImpl.java:254)
at org.apache.ignite.internal.processors.cache.GatewayProtectedCacheProxy.getConfiguration(GatewayProtectedCacheProxy.java:121)```
For both errors I tried to recover by calling InitializeCache() to refresh IIGnite but I get new errors like java.lang.IllegalStateException: Grid is in invalid state to perform this operation. It either not started yet or has already being or have stopped [igniteInstanceName=Dydx.Logistics.Service, state=STOPPED] The issue here is not my appdomain restarting or other similar issues that I have seen in other StackOverflow posts. I run my unit tests continously until the cache fails.
Note that I don't host Ignite in IIS in PROD environments. But this code is easy for DEV environments. Hoping someone can point me in the right direction here...
Exception details:
EXCEPTION #1A - Occurs when calling DataCache.ContainsKey( new Tuple( somestring, somebyte ) )
Failed to serialize object [typeName=String]
at Apache.Ignite.Core.Impl.PlatformJniTarget.InStreamOutLong[TR](Int32 type, Action`1 outAction, Func`3 inAction, Func`2 readErrorAction)
at Apache.Ignite.Core.Impl.PlatformTargetAdapter.DoOutInOpX(Int32 type, Action`1 outAction, Func`2 inErrorAction)
INNER EXCEPTION
{"class org.apache.ignite.binary.BinaryObjectException: Failed to serialize object [typeName=String]\r\n\tat org.apache.ignite.internal.binary.BinaryClassDescriptor.write(BinaryClassDescriptor.java:840)\r\n\tat org.apache.ignite.internal.binary.BinaryWriterExImpl.marshal0(BinaryWriterExImpl.java:223)\r\n\tat org.apache.ignite.internal.binary.BinaryWriterExImpl.marshal(BinaryWriterExImpl.java:164)\r\n\tat org.apache.ignite.internal.binary.BinaryWriterExImpl.marshal(BinaryWriterExImpl.java:151)\r\n\tat org.apache.ignite.internal.binary.BinaryWriterExImpl.writeObjectDetached(BinaryWriterExImpl.java:1506)\r\n\tat org.apache.ignite.internal.processors.platform.utils.PlatformUtils.writeError(PlatformUtils.java:647)\r\n\tat org.apache.ignite.internal.processors.platform.cache.PlatformCache.processInStreamOutLong(PlatformCache.java:771)\r\n\tat org.apache.ignite.internal.processors.platform.PlatformTargetProxyImpl.inStreamOutLong(PlatformTargetProxyImpl.java:67)\r\nCaused by: class org.apache.ignite.IgniteException: Failed to execute native callback because grid is stopping.\r\n\tat org.apache.ignite.internal.processors.platform.callback.PlatformCallbackGateway.enter(PlatformCallbackGateway.java:1200)\r\n\tat org.apache.ignite.internal.processors.platform.callback.PlatformCallbackGateway.memoryReallocate(PlatformCallbackGateway.java:837)\r\n\tat org.apache.ignite.internal.processors.platform.memory.PlatformExternalMemory.reallocate(PlatformExternalMemory.java:48)\r\n\tat org.apache.ignite.internal.processors.platform.memory.PlatformOutputStreamImpl.ensureCapacity(PlatformOutputStreamImpl.java:305)\r\n\tat org.apache.ignite.internal.processors.platform.memory.PlatformOutputStreamImpl.copyAndShift(PlatformOutputStreamImpl.java:331)\r\n\tat org.apache.ignite.internal.processors.platform.memory.PlatformOutputStreamImpl.writeByteArray(PlatformOutputStreamImpl.java:59)\r\n\tat org.apache.ignite.internal.binary.BinaryWriterExImpl.doWriteString(BinaryWriterExImpl.java:443)\r\n\tat org.apache.ignite.internal.binary.BinaryClassDescriptor.write(BinaryClassDescriptor.java:609)\r\n\t... 7 more\r\n"}
Inspecting the Cache object in the locals window just before where the exception is thrown shows that the Cache is already stopped. When I try to expand the data in the locals window I see:
EXCEPTION #1B - class org.apache.ignite.internal.processors.cache.CacheStoppedException: Failed to perform cache operation (cache is stopped): DataCache
at Apache.Ignite.Core.Impl.PlatformJniTarget.OutObjectInternal(Int32 type)
at Apache.Ignite.Core.Impl.Cache.CacheImpl`2.CreateEnumerator(Boolean loc, Int32 peekModes)
at Apache.Ignite.Core.Impl.Cache.CacheImpl`2.GetEnumerator()
at System.Linq.SystemCore_EnumerableDebugView`1.get_Items()
INNER EXCEPTION:
java.lang.IllegalStateException: class org.apache.ignite.internal.processors.cache.CacheStoppedException: Failed to perform cache operation (cache is stopped): DataCache
at org.apache.ignite.internal.processors.cache.GridCacheGateway.enter(GridCacheGateway.java:164)
at org.apache.ignite.internal.processors.cache.GatewayProtectedCacheProxy.onEnter(GatewayProtectedCacheProxy.java:1555)
at org.apache.ignite.internal.processors.cache.GatewayProtectedCacheProxy.iterator(GatewayProtectedCacheProxy.java:1326)
at org.apache.ignite.internal.processors.platform.cache.PlatformCache.processOutObject(PlatformCache.java:1046)
at org.apache.ignite.internal.processors.platform.PlatformTargetProxyImpl.outObject(PlatformTargetProxyImpl.java:105)
Caused by: class org.apache.ignite.internal.processors.cache.CacheStoppedException: Failed to perform cache operation (cache is stopped): DataCache
... 5 more
EXCEPTION #2 - Occurs when calling dataCache.AsCacheQueryable().Where( x => x.Name == "Something" ).SingleOrDefault();
Java exception occurred [class=java.lang.NullPointerException, message=]
Apache.Ignite.Core.Common.IgniteException, Apache.Ignite.Core, Version=2.7.6.40414, Culture=neutral, PublicKeyToken=a487a7ff0b2aaa4a
java.lang.NullPointerException
at org.apache.ignite.internal.processors.cache.IgniteCacheProxyImpl.getConfiguration(IgniteCacheProxyImpl.java:254)
at org.apache.ignite.internal.processors.cache.GatewayProtectedCacheProxy.getConfiguration(GatewayProtectedCacheProxy.java:121)
at org.apache.ignite.internal.processors.platform.cache.PlatformCache.processOutStream(PlatformCache.java:983)
at org.apache.ignite.internal.processors.platform.PlatformTargetProxyImpl.outStream(PlatformTargetProxyImpl.java:93)
Apache.Ignite.Core.Common.JavaException, Apache.Ignite.Core, Version=2.7.6.40414, Culture=neutral, PublicKeyToken=a487a7ff0b2aaa4a
Stack Trace
at Apache.Ignite.Core.Impl.Unmanaged.Jni.Env.ExceptionCheck()
at Apache.Ignite.Core.Impl.Unmanaged.UnmanagedUtils.TargetOutStream(GlobalRef target, Int32 opType, Int64 memPtr)
at Apache.Ignite.Core.Impl.PlatformJniTarget.OutStream[T](Int32 type, Func`2 readAction)
Again, if I inspect the dataCache just before the error point I see java.lang.IllegalStateException: Grid is in invalid state to perform this operation. It either not started yet or has already being or have stopped [igniteInstanceName=Dydx.Logistics.Service, state=STOPPED]
at org.apache.ignite.internal.GridKernalGatewayImpl.illegalState(GridKernalGatewayImpl.java:201)
at org.apache.ignite.internal.GridKernalGatewayImpl.readLock(GridKernalGatewayImpl.java:95)
at org.apache.ignite.internal.IgniteKernal.guard(IgniteKernal.java:3886)
at org.apache.ignite.internal.IgniteKernal.getOrCreateCache0(IgniteKernal.java:3002)
at org.apache.ignite.internal.IgniteKernal.getOrCreateCache(IgniteKernal.java:2992)
at org.apache.ignite.internal.processors.platform.PlatformProcessorImpl.processInStreamOutObject(PlatformProcessorImpl.java:566)
at org.apache.ignite.internal.processors.platform.PlatformTargetProxyImpl.inStreamOutObject(PlatformTargetProxyImpl.java:79)

Related

Android app fails bluetooth connection with ESP when calling connect()

I'm trying to build an Android app in Android Studio using Kotlin to send some simple data between an ESP32 and a mobile over Bluetooth. I've been following along a number of tutorials but just can't seem to get the connection established, permissions and scanning for devices looks to be working correctly. When I call connect() on the socket the app hangs for a few seconds and then crashes with this error:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.btleveller, PID: 28899
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=0, result=-1, data=Intent { (has extras) }} to activity {com.example.btleveller/com.example.btleveller.MainActivity}: java.io.IOException: read failed, socket might closed or timeout, read ret: -1
at android.app.ActivityThread.deliverResults(ActivityThread.java:5368)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:5407)
etc... I can post the full output if it's helpful
My ESP is running some very basic helloworld style code using the NimBLE-Arduino code, programmed through VSCode with the PlatformIO extension. I think this side of it is all working correct as I can see the device in the "nRF Connect" app on my mobile. The scanning is done through the CompanionDeviceManager library:
I thought maybe there was a problem with the UUID I was supplying, or that I needed to make changes for BLE as opposed to regular Bluetooth but so far nothing I've found online has worked. I've also tried using "createL2capChannel()" to create the socket but got stuck on the PSM value. These are the relevant bits of code:
//private val ESP_UUID = UUID.fromString("0000dead-0000-1000-8000-00805F9B34FB")
private val ESP_UUID = UUID.fromString("0000baad-0000-1000-8000-00805F9B34FB")
...
// Look for connection, kicked off by button press
fun lookForConn(view: View) {
val deviceFilter: BluetoothDeviceFilter = BluetoothDeviceFilter.Builder()
.setNamePattern(Pattern.compile("BLE"))
.build()
// The argument provided in setSingleDevice() determines whether a single
// device name or a list of them appears.
val pairingRequest: AssociationRequest = AssociationRequest.Builder()
.addDeviceFilter(deviceFilter)
.setSingleDevice(false)
.build()
// When the app tries to pair with a Bluetooth device, show the
// corresponding dialog box to the user.
deviceManager.associate(pairingRequest,
object : CompanionDeviceManager.Callback() {
override fun onDeviceFound(chooserLauncher: IntentSender) {
startIntentSenderForResult(chooserLauncher,
SELECT_DEVICE_REQUEST_CODE, null, 0, 0, 0)
}
override fun onFailure(error: CharSequence?) {
// Handle the failure.
Log.d("DEVHandler","failed to find dev?")
}
}, null)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
SELECT_DEVICE_REQUEST_CODE -> when(resultCode) {
Activity.RESULT_OK -> {
// The user chose to pair the app with a Bluetooth device.
val deviceToPair: BluetoothDevice? =
data?.getParcelableExtra(CompanionDeviceManager.EXTRA_DEVICE)
Log.d("DEVHandler","try to bond:" + deviceToPair?.name)
deviceToPair?.let { device ->
device.createBond()
val newConn = ConnectThread(deviceToPair).run()
}
}
}
else -> super.onActivityResult(requestCode, resultCode, data)
}
}
private inner class ConnectThread(device: BluetoothDevice) : Thread() {
private var mHaveConn = false
public fun IsConnected(): Boolean {
return mHaveConn
}
private val mmSocket: BluetoothSocket? by lazy(LazyThreadSafetyMode.NONE) {
//device.createRfcommSocketToServiceRecord(ESP_UUID)
device.createInsecureRfcommSocketToServiceRecord(ESP_UUID)
}
public override fun run() {
// Cancel discovery because it otherwise slows down the connection.
BTMan.mBTAdapter?.cancelDiscovery()
mmSocket?.let { socket ->
// Connect to the remote device through the socket. This call blocks
// until it succeeds or throws an exception.
if (socket == null)
Log.d("CONNThread", "Socket is null...")
if (socket.isConnected == true)
Log.d("CONNThread", "Socket is already connected...")
socket.connect()
Log.d("CONNThread", "Made a connection")
// The connection attempt succeeded. Perform work associated with
// the connection in a separate thread.
//manageMyConnectedSocket(socket)
mHaveConn = true
}
}
// Closes the client socket and causes the thread to finish.
fun cancel() {
try {
mmSocket?.close()
} catch (e: IOException) {
Log.e("CONNThread", "Could not close the client socket", e)
}
mHaveConn = false
}
}

Logcat does not show an error message when an exception is thrown in the coroutine (Xiaomi)

It shows only I/Process: Sending signal. PID: xxxxx SIG: 9
I have tried to enable debug mode
System.setProperty(DEBUG_PROPERTY_NAME, DEBUG_PROPERTY_VALUE_ON)
but it did not help
I've also faced this issue sometime back. One of the workaround, is to use a CoroutineExceptionHandler. You can create a handler to print your stack trace as follows.
val exceptionHandler = CoroutineExceptionHandler { _, ex ->
Log.e("CoroutineScope", "Caught ${Log.getStackTraceString(ex)}")
}
And then you can launch your coroutines as someCoroutineScope.launch(exceptionHandler) {}.
Additionally, if you don't want to use handlers in release mode, then you can create your own custom coroutine launcher as an extension function.
fun CoroutineScope.launchCustom(block: suspend CoroutineScope.() -> Unit) : Job {
return if (BuildConfig.DEBUG) {
this.launch(exceptionHandler) {
block()
}
} else {
this.launch {
block()
}
}
}
I just encounter this problem ... I don't know the reason, very few cases I can found(https://juejin.cn/post/7085643598506491918)
Set an extra DefaultUncaughtExceptionHandler works for me:
object ExceptionHandler {
fun setupExceptionHandler() {
val defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler()
Thread.setDefaultUncaughtExceptionHandler { thread, throwable ->
val message = "Uncaught exception in thread ${thread.name}:\n"
Log.e("AndroidRuntime", message, throwable)
defaultUncaughtExceptionHandler?.uncaughtException(thread, throwable)
}
}
}

Microsoft.Azure.Mobile Client - Handling Server Error using custom IMobileServiceSyncHandler - Xamarin Forms

I have implemented the Azure - Offline Sync based on the documentation / Sample provided by Microsoft Sample in my Xamarin Forms Application.
In the sample / documentation provided, they are using the default Service Handler.
// Simple error/conflict handling. A real application would handle the various errors like network conditions,server conflicts and others via the IMobileServiceSyncHandler.
Since I need to implement a retry logic for 3 times if the Pull / Push fails. As per the documentation I have created a custom Service Handler(IMobileServiceSyncHandler).
Please find my code logic here.
public class CustomSyncHandler : IMobileServiceSyncHandler
{
public async Task<JObject> ExecuteTableOperationAsync(IMobileServiceTableOperation operation)
{
MobileServiceInvalidOperationException error = null;
Func<Task<JObject>> tryExecuteAsync = operation.ExecuteAsync;
int retryCount = 3;
for (int i = 0; i < retryCount; i++)
{
try
{
error = null;
var result = await tryExecuteAsync();
return result;
}
catch (MobileServiceConflictException e)
{
error = e;
}
catch (MobileServicePreconditionFailedException e)
{
error = e;
}
catch (MobileServiceInvalidOperationException e)
{
error = e;
}
catch (Exception e)
{
throw e;
}
if (error != null)
{
if(retryCount <=3) continue;
else
{
//Need to implement
//Update failed, reverting to server's copy.
}
}
}
return null;
}
public Task OnPushCompleteAsync(MobileServicePushCompletionResult result)
{
return Task.FromResult(0);
}
}
But I am not sure how to handle / revert server copy in case all the 3 retry failed.
In the TODO sample they where reverting it based on the
MobileServicePushFailedException. But which is available when we implement IMobileServiceSyncHandler.
More over if we include custom IMobileServiceSyncHandler it wont execute the code after PushAsync / PullAsync. Even the try catch wont fire in case any exception.
try
{
await this.client.SyncContext.PushAsync();
await this.todoTable.PullAsync(
//The first parameter is a query name that is used internally by the client SDK to implement incremental sync.
//Use a different query name for each unique query in your program
"allTodoItems",
this.todoTable.CreateQuery());
}
catch (MobileServicePushFailedException exc)
{
if (exc.PushResult != null)
{
syncErrors = exc.PushResult.Errors;
}
}
// Simple error/conflict handling. A real application would handle the various errors like network conditions,
// server conflicts and others via the IMobileServiceSyncHandler.
if (syncErrors != null)
{
foreach (var error in syncErrors)
{
if (error.OperationKind == MobileServiceTableOperationKind.Update && error.Result != null)
{
//Update failed, reverting to server's copy.
await error.CancelAndUpdateItemAsync(error.Result);
}
else
{
// Discard local change.
await error.CancelAndDiscardItemAsync();
}
Debug.WriteLine(#"Error executing sync operation. Item: {0} ({1}). Operation discarded.", error.TableName, error.Item["id"]);
}
}
}
Note
In my application I am only trying to achieve retry for 3 time in case any server error. I am not looking for to resolve conflicts. Thant is the reason I haven't added the code for the same.
If someone came across similar issues and resolved it please help.
Stez.
You say you aren't trying to resolve conflicts, but you need to resolve them one way or another (without telling the user what's going on, perhaps) by accepting the server version of the object or updating the client operation. Otherwise it will just keep telling you about the same conflict each time it retries the operation.
You need to have a subclass of the Microsoft.WindowsAzure.MobileServices.Sync.MobileServiceSyncHandler class, which overrides OnPushCompleteAsync() in order to handle conflicts and other errors. Let's call the class SyncHandler:
public class SyncHandler : MobileServiceSyncHandler
{
public override async Task OnPushCompleteAsync(MobileServicePushCompletionResult result)
{
foreach (var error in result.Errors)
{
await ResolveConflictAsync(error);
}
await base.OnPushCompleteAsync(result);
}
private static async Task ResolveConflictAsync(MobileServiceTableOperationError error)
{
Debug.WriteLine($"Resolve Conflict for Item: {error.Item} vs serverItem: {error.Result}");
var serverItem = error.Result;
var localItem = error.Item;
if (Equals(serverItem, localItem))
{
// Items are the same, so ignore the conflict
await error.CancelAndUpdateItemAsync(serverItem);
}
else // check server item and local item or the error for criteria you care about
{
// Cancels the table operation and discards the local instance of the item.
await error.CancelAndDiscardItemAsync();
}
}
}
Include an instance of this SyncHandler() when you initialize your MobileServiceClient:
await MobileServiceClient.SyncContext.InitializeAsync(store, new SyncHandler()).ConfigureAwait(false);
Read up on the MobileServiceTableOperationError to see other conflicts you can handle as well as its methods to allow resolving them.
The exception carries with it a copy of the server version. In my implementation of IMobileServiceSyncHandler I therefore just return error.Value and this seems to work.
A more extensive example of this kind of logic can be found in this MSDN blog.
The same author has another example where he shows how you can resolve the conflict in favour of the server copy or the client copy, here.

Hazelcast failed to create an ObjectName when using file|http(s) protocol

after running on this exception using hazelcast 3.6 :
java.lang.IllegalArgumentException: Failed to create an ObjectName
at
com.hazelcast.jmx.HazelcastMBean.setObjectName(HazelcastMBean.java:116)
at
com.hazelcast.jmx.ConnectionManagerMBean.(ConnectionManagerMBean.java:39)
at
com.hazelcast.jmx.InstanceMBean.createMBeans(InstanceMBean.java:74)
at com.hazelcast.jmx.InstanceMBean.(InstanceMBean.java:67) at
com.hazelcast.jmx.ManagementService.(ManagementService.java:67)
at
com.hazelcast.instance.HazelcastInstanceImpl.(HazelcastInstanceImpl.java:136)
at
com.hazelcast.instance.HazelcastInstanceFactory.constructHazelcastInstance(HazelcastInstanceFactory.java:160)
at
com.hazelcast.instance.HazelcastInstanceFactory.getOrCreateHazelcastInstance(HazelcastInstanceFactory.java:98)
at
com.hazelcast.cache.impl.HazelcastServerCachingProvider.getOrCreateInstance(HazelcastServerCachingProvider.java:98)
at
com.hazelcast.cache.impl.HazelcastServerCachingProvider.createHazelcastCacheManager(HazelcastServerCachingProvider.java:64)
at
com.hazelcast.cache.impl.HazelcastServerCachingProvider.createHazelcastCacheManager(HazelcastServerCachingProvider.java:42)
at
com.hazelcast.cache.impl.AbstractHazelcastCachingProvider.getCacheManager(AbstractHazelcastCachingProvider.java:94)
at
com.hazelcast.cache.HazelcastCachingProvider.getCacheManager(HazelcastCachingProvider.java:131)
I took look at this part of the code, which is causing the error, on File: HazelcastServerCachingProvider.java (starting at line: 78 ):
String location = properties.getProperty(HazelcastCachingProvider.HAZELCAST_CONFIG_LOCATION);
// If config location is specified, get instance through it.
if (location != null) {
URI uri = new URI(location);
String scheme = uri.getScheme();
if (scheme == null) {
// It is a place holder
uri = new URI(System.getProperty(uri.getRawSchemeSpecificPart()));
}
ClassLoader theClassLoader = classLoader == null ? getDefaultClassLoader() : classLoader;
final URL configURL;
if ("classpath".equals(scheme)) {
configURL = theClassLoader.getResource(uri.getRawSchemeSpecificPart());
} else if ("file".equals(scheme) || "http".equals(scheme) || "https".equals(scheme)) {
configURL = uri.toURL();
} else {
throw new URISyntaxException(location, "Unsupported protocol in configuration location URL");
}
try {
Config config = new XmlConfigBuilder(configURL).build();
config.setClassLoader(theClassLoader);
**HERE BAD INSTANCENAME IS GENERATED**
config.setInstanceName(configURL.toString());
return HazelcastInstanceFactory.getOrCreateHazelcastInstance(config);
} catch (Exception e) {
throw ExceptionUtil.rethrow(e);
}
}
When using file or http(s) protocol in the passed hazelcast_config_location, we are going to fail creating the mbean, since the hazelCastInstanceName should not contain the character ‘:’, which is unfortunately part of the configURI name.
Is this a Bug or do I overlooked something??
Thanks for your response
javax ObjectName class does not support the character : and throws a MalformedObjectNameException. Hazelcast processes this exception and throws IllegalArgumentException with the message comes from it.
https://github.com/hazelcast/hazelcast/blob/master/hazelcast/src/main/java/com/hazelcast/internal/jmx/HazelcastMBean.java#L121
https://docs.oracle.com/javase/7/docs/api/javax/management/ObjectName.html
Edit: quote function should've handled it in your case however, there is a bug in hz apparently. See: https://github.com/hazelcast/hazelcast/blob/master/hazelcast/src/main/java/com/hazelcast/internal/jmx/ConnectionManagerMBean.java#L38

Entity Framework 5 - Implementing SQL Server "Execute As User"

I am writing a database application using Visual Studio 2012 with Entity Framework 5 and SQL Server 2008. I would like Entity Framework to impersonate a SQL Server user (i.e. user without a login). I have created a new constructor for the DB context MyDatabaseEntities which includes an argument for the name of the user to impersonate. Here is the code that I've written:
public partial class MyDatabaseEntities
{
private String _impersonateUser = null;
public MyDatabaseEntities(String impersonateUser)
: base("MyConnectionString")
{
_impersonateUser = impersonateUser;
this.Database.Connection.StateChange += Connection_StateChange;
}
void Connection_StateChange(object sender, StateChangeEventArgs e)
{
if (e.CurrentState == ConnectionState.Open && e.OriginalState != ConnectionState.Open)
{
using (var cmd = this.Database.Connection.CreateCommand())
{
cmd.CommandType = CommandType.Text;
cmd.Parameters.Add(new SqlParameter("user", _impersonateUser));
cmd.CommandText = "EXECUTE AS USER = #user";
cmd.ExecuteNonQuery();
}
}
}
I had to add the check...
if (e.CurrentState == ConnectionState.Open && e.OriginalState != ConnectionState.Open)
...because the method Connection_StateChange method seems to execute even when the state hasn't changed. Then problem is that when I run the code twice,
public void RunSimpleQuery()
{
using (MyDatabaseEntities context = new MyDatabaseEntities("UserName"))
{
var result = context.TableName.ToList();
}
}
...Entity Framework throws a SqlException:
A severe error occurred on the current command. The results, if
any, should be discarded.\r\nA severe error occurred on the current
command. The results, if any, should be discarded.
Any ideas?
Update 1
I in my code above, I changed...
cmd.CommandText = "EXECUTE AS USER = #user;";
...to...
cmd.CommandText = "REVERT; EXECUTE AS USER = #user;";
...and I still get the same SqlException error.
The problem is that EF closes connection when it doesn't need it and returns it back to the pool. So when it executes some SQL again it request new connection from the pool where your event may not be initialized. But again I believe that you should try to solve this with manually controlling connection lifetime to have both benefit of connection pooling and be able to meet your requirements.
I know is an old question, but maybe will be useful for someone.
I did in a different way, using your code...
Instead of
Connection_StateChanged event
I create two methods in the same class:
public void ChangeUser(String sUser)
{
if(Database.Connection.State != ConnectionState.Open)
Database.Connection.Open();
using (var cmd = Database.Connection.CreateCommand())
{
cmd.CommandType = CommandType.Text;
cmd.Parameters.Add(new SqlParameter("user", sUser));
cmd.CommandText = "EXECUTE AS USER = #user;";
cmd.ExecuteNonQuery();
}
}
public void Revert()
{
if (Database.Connection.State != ConnectionState.Open)
Database.Connection.Open();
using (var cmd = Database.Connection.CreateCommand())
{
cmd.CommandType = CommandType.Text;
cmd.CommandText = "REVERT;";
cmd.ExecuteNonQuery();
}
}
I use it before and after execute stored procedure,
using (var db = new MyDatabaseEntities())
{
db.ChangeUser(model.Username);
var result = db.Something();
db.Revert();
return result;
}
It works fine with SPs and it doesn't throw an exception even after many executions. If I could catch an event after command execute, maybe all be encapsulated on MyDatabaseEntities.

Resources