Looping the if statement to restart a service in case of failure - c#

I have a code where I am checking if the service that I am passing as a parameter in the method is running then stop it & start it with an interval of 10 seconds, basically it's just a restart method. However, is it possible to use a loop with a timer to so that in case after stopping if the service is not starting keep trying to start back up until it is running back again.
The library I am using is System.ServiceProcess
Here's the method I've so far.
public static bool RestartService(string serviceName)
{
bool result = false;
using (ServiceController controller = new ServiceController(serviceName))
{
try
{
if (controller.Status != ServiceControllerStatus.Stopped)
{
controller.Stop();
controller.WaitForStatus(ServiceControllerStatus.Stopped,
TimeSpan.FromSeconds(10));
}
if (controller.Status != ServiceControllerStatus.Running)
{
controller.Start();
controller.WaitForStatus(ServiceControllerStatus.Running,
TimeSpan.FromSeconds(10));
}
if (controller.Status == ServiceControllerStatus.Running)
{
result = true;
}
}
catch (Exception ex)
{
_logger.Error($"RestartService {serviceName} failed,
exception_message: {ex.Message}");
}
}
return result;
}

is it possible to use a loop with a timer to so that in case after stopping if the service is not starting keep trying to start back up until it is running back again.
The method can be called from a Timer (which is probably a good idea so that it runs in the background).
Converting your code to do retrying until success is as simple as changing if to while:
public static bool RestartService(string serviceName)
{
bool result = false;
using (ServiceController controller = new ServiceController(serviceName))
{
try
{
while (controller.Status != ServiceControllerStatus.Stopped)
{
controller.Stop();
controller.WaitForStatus(ServiceControllerStatus.Stopped,
TimeSpan.FromSeconds(10));
}
while (controller.Status != ServiceControllerStatus.Running)
{
controller.Start();
controller.WaitForStatus(ServiceControllerStatus.Running,
TimeSpan.FromSeconds(10));
}
result = true;
}
catch (Exception ex)
{
_logger.Error($"RestartService {serviceName} failed,
exception_message: {ex.Message}");
}
}
return result;
}

Related

Multithreaded Client

I created a client-server in C#, and everything works, and I thought of adding the ability to cancel requests that timed out, so at the server-side, each request I send starts a new Timer, and when it runs out of time, I send another request that says ABORT {MessageId}.
This is what I implemented so far, but for some reason, it won't terminate the Thread, when I debugged I saw that it finds the correct thread but doesn't terminate it.
Perhaps there is even a better way for implementing this...
Dictionary<int, Thread> threads = new();
private static void ReceiveResponse()
{
//I get the message (body)
string? response = Util.Bytes2String(body);
if (response == null)
return;
//There is no need to create a new Thread for aborting a Thread...
if (ShouldAbort(response))
return;
Thread thread = new(() =>
{
HandleCommand(response, msgId);
Thread.CurrentThread.IsBackground = true;
});
threads.Add(msgId, thread);
thread.Start();
Console.WriteLine($"Thread {thread.ManagedThreadId} was created for Request No. {msgId}");
}
private static bool ShouldAbort(string command)
{
if (!Util.IsStringValid(command))
return false;
if (command.StartsWith(MessageType.ABORT_TASK))
{
if (int.TryParse(command.Split('\t')[1], out int id)) //Get the ID of the message to abort
{
if (threads.ContainsKey(id))
{
AbortThreadAt(id);
return true;
}
else
Console.WriteLine($"Couldn't abort Request No. {id} because it doesn't exist");
return false;
}
{
Console.WriteLine($"Unable to stop the Thread.");
return true;
}
}
return false;
}
private static void AbortThreadAt(int i)
{
try
{
Thread thread = threads[i];
threads.Remove(i);
Console.WriteLine($"Thread {thread.ManagedThreadId} for Request No. {i} was aborted");
thread.Interrupt();
}
catch (Exception) { }
}

Xamarin.Forms (Android) Bluetooth intermittently working

Scenario:
I am building an Android app using Xamarin.Forms that will be deployed to a group of devices. All but one of the devices will be doing some data collection, and the remaining device will be the "hub" to aggregate all of the data and do some reporting. I am using Bluetooth for the device-to-device communication. The 'hub', labelled the master, acts as the client, and all of the collectors act as the server. I have a prototype working with a single server and client...almost.
Occasionally the client/master will be unable to read from the server/collector. I am struggling to find the reason for why this is and would appreciate any help.
Symptoms:
The client's call to .Read() from the InputStream will occasionally block indefinitely, even though the server has written to the output stream. I've added a timeout to this call to prevent the app from getting stuck entirely.
This happens intermittently, but I've found some pattern to when it works and when it doesn't
It seems to be related to the 'server' app, and not the client. The client can remain open, running, and initiate the request to connect to the server as often as needed.
It always works the first time the 'server' app is launched and connected to. It ususally works the second time. By the third connection, .Read() will consistently block/timeout. Closing and reopening the app on the server "cleans the slate" so to speak and it will work again.
Once it starts failing, it seems to be 'stuck' in a failed state.
Removing the app from the foreground (but not closing/killing it) seems to correct the faulted state, and the connection/read will happen successfully as long as the app/UI remains in the background. Once restored to the foreground, it starts failing again.
Code:
All of the bluetooth handling is done by a single class/service that I'm injecting using Xamarin.Forms DependencyService. All of the devices will, on startup (via the constructor of this class), loop indefinitely on a background thread, waiting for connections and repeating. Much of this bluetooth code is based on the Bluetooth Chat example, as well as some other online resources I've found (some android native/java, some Xamarin/C#)
The master will, on demand (triggered by press of a button in the UI), attempt to connect to any collectors (via bonded bluetooth devices) and read data from them. There is also a simple UI component which essentially serves as a console log.
Here is the service class in its entirety.
public class GameDataSyncService : IGameDataSyncService
{
private const string UUID = "8e99f5f1-4a07-4268-9686-3a288326e0a2";
private static Task acceptLoopTask;
private static Task syncDataTask;
private static readonly object locker = new object();
private static bool running = false;
public event EventHandler<DataSyncMessage> MessageBroadcast;
public GameDataSyncService()
{
// Every device will listen and accept incoming connections. The master will make the connections.
lock (locker)
{
if (acceptLoopTask == null)
{
acceptLoopTask = Task.Factory.StartNew(AcceptLoopWorker, TaskCreationOptions.LongRunning);
}
}
}
public void SyncData()
{
lock (locker)
{
if (running)
{
BroadcastMessage("Previous data sync is still running.", DataSyncMessageType.Warning);
return;
}
else
{
running = true;
syncDataTask = Task.Factory.StartNew(SyncDataWorker);
}
}
}
private void BroadcastMessage(string message, DataSyncMessageType type = DataSyncMessageType.Info)
{
MessageBroadcast?.Invoke(this, new DataSyncMessage { Text = message, Type = type });
}
private async Task AcceptLoopWorker()
{
int count = 0;
while (true)
{
BluetoothServerSocket serverSocket = null;
BluetoothSocket clientSocket = null;
try
{
BroadcastMessage($"Listening for incoming connection...", DataSyncMessageType.Debug);
serverSocket = BluetoothAdapter.DefaultAdapter.ListenUsingRfcommWithServiceRecord(nameof(GameDataSyncService), Java.Util.UUID.FromString(UUID));
clientSocket = serverSocket.Accept(); // This call blocks until a connection is established.
BroadcastMessage($"Connection received from {clientSocket.RemoteDevice.Name}. Sending data...", DataSyncMessageType.Info);
var bytes = Encoding.UTF8.GetBytes($"Hello World - {string.Join(" ", Enumerable.Repeat(Guid.NewGuid(), ++count))}");
await clientSocket.OutputStream.WriteAsync(bytes, 0, bytes.Length);
clientSocket.OutputStream.Flush();
// Give the master some time to close the connection from their end
await Task.Delay(1000*3);
}
catch (Exception ex)
{
BroadcastMessage($"{ex.GetType().FullName}: {ex.Message}", DataSyncMessageType.Debug);
}
finally
{
try { clientSocket?.InputStream?.Close(); } catch { }
try { clientSocket?.InputStream?.Dispose(); } catch { }
try { clientSocket?.OutputStream?.Close(); } catch { }
try { clientSocket?.OutputStream?.Dispose(); } catch { }
try { clientSocket?.Close(); } catch { }
try { clientSocket?.Dispose(); } catch { }
try { serverSocket?.Close(); } catch { }
try { serverSocket?.Dispose(); } catch { }
BroadcastMessage($"Connection closed.", DataSyncMessageType.Debug);
}
}
}
private async Task SyncDataWorker()
{
BroadcastMessage($"Beginning data sync...");
foreach (var bondedDevice in BluetoothAdapter.DefaultAdapter.BondedDevices.OrderBy(d => d.Name))
{
BluetoothSocket clientSocket = null;
try
{
clientSocket = bondedDevice.CreateRfcommSocketToServiceRecord(Java.Util.UUID.FromString(UUID));
BroadcastMessage($"Connecting to {bondedDevice.Name}...");
try
{
clientSocket.Connect();
}
catch
{
BroadcastMessage($"Connection to {bondedDevice.Name} failed.", DataSyncMessageType.Error);
}
while (clientSocket.IsConnected)
{
byte[] buffer = new byte[1024];
var readTask = clientSocket.InputStream.ReadAsync(buffer, 0, buffer.Length);
if (await Task.WhenAny(readTask, Task.Delay(1000)) != readTask)
{
BroadcastMessage($"Read timeout...", DataSyncMessageType.Error);
break;
}
int bytes = readTask.Result;
BroadcastMessage($"Read {bytes} bytes.", DataSyncMessageType.Success);
if (bytes > 0)
{
var text = Encoding.UTF8.GetString(buffer.Take(bytes).ToArray());
BroadcastMessage(text, DataSyncMessageType.Success);
break;
}
}
}
catch (Exception ex)
{
BroadcastMessage($"{ex.GetType().FullName}: {ex.Message}", DataSyncMessageType.Debug);
}
finally
{
try { clientSocket?.InputStream?.Close(); } catch { }
try { clientSocket?.InputStream?.Dispose(); } catch { }
try { clientSocket?.OutputStream?.Close(); } catch { }
try { clientSocket?.OutputStream?.Dispose(); } catch { }
try { clientSocket?.Close(); } catch { }
try { clientSocket?.Dispose(); } catch { }
}
}
await Task.Delay(1000 * 3);
BroadcastMessage($"Data sync complete!");
lock (locker)
{
running = false;
}
}
}
What I've tried (nothing below has had any effect):
Most of these were from 'solutions' from other stackoverflow posts.
Adding arbitrary delays into the mix
Making sure to explicitly close/dispose everything, in order, including the streams
Tried replacing the socket handling with their 'Insecure' counterparts.
Adjusting my read timeout to something arbitrarily long, in case a second wasn't enough.
Disabling/Re-enabling bluetooth on the server/collector before .Accept() ing a new connection (resorted to trying random stuff by this point)
Video:
I took a video of this happening.
The tablet in the back is the collector/server The tablet in the foreground is the master/client. When the video starts, the client is displaying some previous attempts, and the server app is in the background (but running). I demonstrate that the .Read works when the collector/server app is in the background, but not the foreground. Each request to begin data sync has a corresponding entry to the "console" (or a warning if I pressed it too soon)
https://youtu.be/NGuGa7upCU4
Summary:
To the best of my knowledge, my code is correct. I have no idea what else to change/fix to get this working more reliably. The actual connection seems like it is successful (based on logs from the server/collector, unfortunately not shown in the video), but the issue lies somewhere in the .Write (or .Read). ANy help, suggestions, or insight would be awesome.
Try the following, changed all to using:
private async Task AcceptLoopWorker()
{
int count = 0;
while (true)
{
try
{
BroadcastMessage("Listening for incoming connection...", DataSyncMessageType.Debug);
using (var serverSocket = BluetoothAdapter.DefaultAdapter.ListenUsingRfcommWithServiceRecord(nameof(GameDataSyncService), Java.Util.UUID.FromString(UUID)))
using (var clientSocket = serverSocket.Accept()) // This call blocks until a connection is established.
{
BroadcastMessage(string.Format("Connection received from {0}. Sending data...", clientSocket.RemoteDevice.Name), DataSyncMessageType.Info);
var bytes = System.Text.Encoding.UTF8.GetBytes(string.Format("Hello World - {0}", string.Join(" ", Enumerable.Repeat(Guid.NewGuid(), ++count))));
await clientSocket.OutputStream.WriteAsync(bytes, 0, bytes.Length);
}
await Task.Delay(1000 * 3); // Give the master some time to close the connection from their end
}
catch (Java.IO.IOException ex)
{
BroadcastMessage(string.Format("IOException {0}: {1}", ex.GetType().FullName, ex.Message), DataSyncMessageType.Debug);
}
catch (Java.Lang.Exception ex)
{
BroadcastMessage(string.Format("Exception {0}: {1}", ex.GetType().FullName, ex.Message), DataSyncMessageType.Debug);
}
}
}
private async Task SyncDataWorker()
{
BroadcastMessage("Beginning data sync...");
foreach (var bondedDevice in BluetoothAdapter.DefaultAdapter.BondedDevices.OrderBy(d => d.Name))
{
try
{
using (var clientSocket = bondedDevice.CreateRfcommSocketToServiceRecord(Java.Util.UUID.FromString(UUID)))
{
BroadcastMessage(string.Format("Connecting to {0}...", bondedDevice.Name));
if (!clientSocket.IsConnected)
{
clientSocket.Connect();
}
if (clientSocket.IsConnected)
{
byte[] buffer = new byte[1024];
var readTask = clientSocket.InputStream.ReadAsync(buffer, 0, buffer.Length);
if (await Task.WhenAny(readTask, Task.Delay(1000)) != readTask)
{
BroadcastMessage("Read timeout...", DataSyncMessageType.Error);
break;
}
int bytes = readTask.Result;
BroadcastMessage(string.Format("Read {0} bytes.", bytes), DataSyncMessageType.Success);
if (bytes > 0)
{
var text = System.Text.Encoding.UTF8.GetString(buffer.Take(bytes).ToArray());
BroadcastMessage(text, DataSyncMessageType.Success);
break;
}
}
else
{
BroadcastMessage("Not Connected...", DataSyncMessageType.Error);
}
}
}
catch (Java.IO.IOException ex)
{
BroadcastMessage(string.Format("IOException {0}: {1}", ex.GetType().FullName, ex.Message), DataSyncMessageType.Debug);
}
catch (Java.Lang.Exception ex)
{
BroadcastMessage(string.Format("Exception {0}: {1}", ex.GetType().FullName, ex.Message), DataSyncMessageType.Debug);
}
}
await Task.Delay(1000 * 3);
BroadcastMessage("Data sync complete!");
lock (locker)
{
running = false;
}
}

C# Recursive function approach?

I have a recursive function in a windows service. This function upon completion rewinds itself as it has been repeated multiple times in recursion. Isn't that an overhead ?
Is there any way to avoid unwinding ? Is there any better approach?
Edit : In this method, I get 100 records from DB and then process them and then get another 100 and so on till all the records in DB have been processed.
Also, there is no limit of how many total records there might be in the db so this function can repeat itself quite a lot.
public void ServiceFunctionality()
{
try
{
// Get Data From WEBAPI
HttpClient client = new HttpClient();
HttpResponseMessage response = response = client.GetAsync("webapi url link").Result;
Response<ServiceWrapper> objResponse = response.Content.ReadAsAsync<Response<ServiceWrapper>>().Result;
if (objResponse != null)
{
if (objResponse.isSuccess == true)
{
listContact = objResponse.data.lContact;
int MaxPKinSelectedRecords = objResponse.data.MaxPKinSelectedRecords;
int MaxPKinTotalRecords = objResponse.data.MaxPKinTotalRecords;
if (listContact != null && listContact.Count>0)
{
try
{
Parallel.ForEach(listContact, contact =>
{
// some code...
});
// Recursive Call
if (MaxPKinTotalRecords != MaxPKinSelectedRecords)
{
ServiceFunctionality();
}
}
catch (Exception ex)
{
// Logging
}
}
}
else
{
// Logging
}
}
else
{
// Logging
}
}
catch (Exception ex)
{
// Logging
}
}
You can always unwind to a while loop. Because your calls aren't altering state, this is trival.
public void ServiceFunctionality()
{
bool done = false;
while(!done) {
try
{
done = true; //if we don't reset this, we're done.
// Get Data From WEBAPI
HttpClient client = new HttpClient();
HttpResponseMessage response = response = client.GetAsync("webapi url link").Result;
Response<ServiceWrapper> objResponse = response.Content.ReadAsAsync<Response<ServiceWrapper>>().Result;
if (objResponse != null)
{
if (objResponse.isSuccess == true)
{
listContact = objResponse.data.lContact;
int MaxPKinSelectedRecords = objResponse.data.MaxPKinSelectedRecords;
int MaxPKinTotalRecords = objResponse.data.MaxPKinTotalRecords;
if (listContact != null && listContact.Count>0)
{
try
{
Parallel.ForEach(listContact, contact =>
{
// some code...
});
// set loop variable
if (MaxPKinTotalRecords != MaxPKinSelectedRecords)
{
done = false;
}
}
catch (Exception ex)
{
// Logging
}
}
}
else
{
// Logging
}
}
else
{
// Logging
}
}
catch (Exception ex)
{
// Logging
}
}
}
Do not use recursion for calling a function whenever you have alternate suitable solution. I personally almost never do
I have tried to keep it same other than using a while..
Do not forget to break your loop. I tried to handle this thing but still
Just to be very careful, never take a risk of infinite loop on server I took maxPossibleIterations. So that in case of any mistake your web service server would not have to go for infinite iterations
public void ServiceFunctionality()
{
long maxPossibleIterations = 999999;
try
{
while (true)
{
maxPossibleIterations++;
// Get Data From WEBAPI
HttpClient client = new HttpClient();
HttpResponseMessage response = response = client.GetAsync("webapi url link").Result;
Response<ServiceWrapper> objResponse = response.Content.ReadAsAsync<Response<ServiceWrapper>>().Result;
if (objResponse != null)
{
if (objResponse.isSuccess == true)
{
listContact = objResponse.data.lContact;
int MaxPKinSelectedRecords = objResponse.data.MaxPKinSelectedRecords;
int MaxPKinTotalRecords = objResponse.data.MaxPKinTotalRecords;
if (listContact != null && listContact.Count>0)
{
try
{
Parallel.ForEach(listContact, contact =>
{
// some code...
});
if (MaxPKinTotalRecords == MaxPKinSelectedRecords)
{
break;
}
}
catch (Exception ex)
{
// Logging
}
}
else
break; //Important
}
else
{
// Logging
break;
}
}
else
{
// Logging
break;
}
} // End while
}
catch (Exception ex)
{
// Logging
}
}

Synchronization-Thread with Server every 5 secs

I have a server-client environment, where the client connects and synchronizes data with the server every 5 second.
For synchronizing I use a background thread on the client which works fine, but on one specific hardware the method GetNetworkAvailable throws out of memory exceptions occasionaly. The errors occur whitout logic, so I guess somethings just not good with this hardware. Anyways I'd like to get your opinion on my background - polling function.
private void SynchronizedWorker()
{
bool initialization = true;
int initializationTries = 0;
// Sync loop
while (!_shouldStop)
{
// Initialize locals
int syncInterval = _syncInterval; // Reset Sync Interval to default
SyncStatus syncStatus = SyncStatus; // Get current Status
bool hasNetworkConnection = true; // Has Network connection
try
{
//*******************************************
// Check Network connection
//*******************************************
if (!NetworkInterface.GetIsNetworkAvailable())
{
hasNetworkConnection = false;
_syncResetEvent.Set();
syncStatus = SyncStatus.Offline;
}
else if (syncStatus == SyncStatus.Offline) // Is in offline - State, but Network available again recognize going online
{
_syncResetEvent.Set();
hasNetworkConnection = IsServiceAvailable();
// Sync-Status stays offline
if (!hasNetworkConnection)
{
// Wait 1 minute, before retry
syncInterval = 60000;
}
}
//*******************************************
// Proceed with Syncronisation
//*******************************************
if (hasNetworkConnection)
{
syncStatus = SyncStatus.Ok;
// Try Initialization
if (initialization)
{
try
{
// Sync initialization here...
// ..............................
////////////////////////////////////
}
catch (Exception ex)
{
log.LogError(string.Format("Initialization Try {0}", initializationTries), ex);
syncStatus = SyncStatus.InitializationFailed;
}
}
// To many Init-Tries --> Stop
if (initializationTries > 1)
{
// Proceed
_syncResetEvent.Set();
_syncStatus = syncStatus;
break; // Stop Synch
}
// Debug
var sw = System.Diagnostics.Stopwatch.StartNew();
// Do Up/Download
if (!initialization)
{
try
{
// Synchronisation with service here...
// ..............................
////////////////////////////////////
// Proceed
_syncResetEvent.Set();
}
catch (Exception ex)
{
log.LogError("Download", ex);
syncStatus = SyncStatus.SynchFailed;
}
}
}
// Set Sync status
_syncStatus = syncStatus;
}
catch (Exception ex)
{
log.LogError("Sync-Worker", ex);
_syncStatus = Core.Sync.SyncStatus.SynchFailed;
// Proceed
_syncResetEvent.Set();
// Reset Force
_syncForce = false;
}
finally
{
// Set Completed
if (OnSyncCompleted != null)
{
OnSyncCompleted(downloaded, uploaded, executed);
}
// Always Wait for Interval
DateTime sleepuntil = DateTime.Now.AddMilliseconds(syncInterval);
while (sleepuntil > DateTime.Now && !_shouldStop && !_syncForce)
{
// Sleep
Thread.Sleep(100);
}
}
}
// Stop
_syncStatus = SyncStatus.Unknown;
}

How do I properly close serial port connection and thread it runs in?

I have an serial port read running on a background thread, but everytime I try to close it, I get an exception. Usually an IO-exception.
It is as if the read continues on eventhough I close the thread.
This is my current code:
EDIT: I changed the code, removed the checks on threatstate.
public bool Connect(string portName)
{
try
{
sp = new SerialPort(portName, BaudRate);
sp.Open();
sp.DtrEnable = true;
cf = SingletonFormProvider.GetInstance<ConnectionForm>(null);
_continue = true;
readThread = new Thread(Read);
readThread.Start();
return true;
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
return false;
}
}
public void Disconnect()
{
if (IsConnectionOpen)
{
_continue = false;
readThread.Abort();
while (readThread.ThreadState == ThreadState.AbortRequested)
{ }
sp.Close();
readThread.Join();
}
}
private void Read()
{
while (_continue)
{
try
{
string message = sp.ReadLine();
cf.WriteLog(message);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
_continue = false;
readThread.Join();
sp.Close();
}
}
}
You do know that what thread.Abort() does is throw a ThreadAbortException in the thread in question, right? In the thread you catch all exceptions that inherited from Exception. I believe that includes the abort exception. If you really must call Abort, you may want to close the serial port first since I believe that will cause any pending calls to return.
Join your read thread before you close the serial port:
public void Disconnect()
{
if (IsConnectionOpen)
{
_continue = false;
readThread.Join();
sp.Close();
}
}

Categories