How to make a Windows Service terminate when one of its sub-threads terminate - windows

in the ServiceStart() call of a windows service, I create a thread and start it.
Thread1 = New TThread1(false)
In the Execute procedure of the subthread, there is a loop that runs forever and does that the service is supposed to do.
The problem is that when I get an error in this thread, I want to terminate the thread, and stop the service too.
How can I get the service to stop itself if a thread that it has started stops (fails).

A possibility is to use watchdog timers:
in your thread you reset the timer (eg. every time you enter the loop).
when interval of timer is expired, you know that the thread is probably not working anymore, so you can restart the service or what ever...

A better approach might be to catch exceptions in the thread and log them. Or you could catch the exception, log it, then stop the service. That way you are in control of the service stopping and you also have some insight into the errors being generated.

make a call to stop service :
bool StopService(string svr_name)
{
bool ret = false;
if (svr_name.Length > 0)
{
try
{
ServiceController sc = new ServiceController(svr_name);
if (sc.Status == ServiceControllerStatus.Stopped)
{
return true;
}
sc.Stop();
}
catch (Exception)
{
return false;
}
}
return ret;
}

Related

Masstransit How to disconnect from from RabbitMq

I am using Masstransit with RabbitMQ. As part of some deployment procedure, At some point in time I need my service to disconnect and stop receiving any messages.
Assuming that I won't need the bus until the next restart of the service, will it be Ok to use bus.StopAsync()?
Is there a way to get list of end points and then remove them from listining ?
You should StopAsync the bus, and then when ready, call StartAsync to bring it back up (or start it at the next service restart).
To stop receiving messages without stopping the buss I needed a solution that will avoid the consume message pipeline from consuming any type of message. I tried with observers but unsuccessfully. My solution came up with custom consuming message filter.
The filter part looks like this
public class ComsumersBlockingFilter<T> :
IFilter<ConsumeContext<T>>
where T : class
{
public void Probe(ProbeContext context)
{
var scope = context.CreateFilterScope("messageFilter");
}
public async Task Send(ConsumeContext<T> context, IPipe<ConsumeContext<T>> next)
{
// Check if the service is degraded (true for this demo)
var isServiceDegraded = true;
if (isServiceDegraded)
{
//Suspend the message for 5 seconds
await Task.Delay(TimeSpan.FromMilliseconds(5000), context.CancellationToken);
if (!context.CancellationToken.IsCancellationRequested)
{
//republish the message
await context.Publish(context.Message);
Console.WriteLine($"Message {context.MessageId} has been republished");
}
// NotifyConsumed to avoid skipped message
await context.NotifyConsumed(TimeSpan.Zero, "messageFilter");
}
else
{
//Next filter in the pipe is called
await next.Send(context);
}
}
}
The main idea is to delay with cancellation token and the republish the message. After that call contect.NotifyConsumed to avoid the next pipeline filters and return normally.

How to call kafkaconsumer api from partition assignor' s implementation

I have implemented my own partition assignment strategy by implementing RangeAssignor in my spring boot application.
I have overridden its subscriptionUserData method and adding some user data. Whenever this data is getting changed I want to trigger partition rebalance by invoking below kafkaConsumer's api
kafkaconsumer apis enforce rebalance
I am not sure how can I get the object of kafka consumer and invoke this api.
Please suggest
You can call consumer.wakeup() function
consumer.wakeup() is the only consumer method that is safe to call from a different thread. Calling wakeup will cause poll() to exit with WakeupException, or if consumer.wakeup() was called while the thread was not waiting on poll, the exception will be thrown on the next iteration when poll() is called. The WakeupException doesn’t need to be handled, but before exiting the thread, you must call consumer.close(). Closing the consumer will commit off‐ sets if needed and will send the group coordinator a message that the consumer is leaving the group. The consumer coordinator will trigger rebalancing immediately
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
System.out.println("Starting exit...");
consumer.wakeup(); **//1**
try {
mainThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
} });
...
Duration timeout = Duration.ofMillis(100);
try {
// looping until ctrl-c, the shutdown hook will cleanup on exit
while (true) {
ConsumerRecords<String, String> records =
movingAvg.consumer.poll(timeout);
System.out.println(System.currentTimeMillis() +
"-- waiting for data...");
for (ConsumerRecord<String, String> record : records) {
System.out.printf("offset = %d, key = %s, value = %s\n",
record.offset(), record.key(), record.value());
}
for (TopicPartition tp: consumer.assignment())
System.out.println("Committing offset at position:" +
consumer.position(tp));
movingAvg.consumer.commitSync();
}
} catch (WakeupException e) {
// ignore for shutdown. **//2**
} finally {
consumer.close(); **//3**
System.out.println("Closed consumer and we are done");
}
ShutdownHook runs in a separate thread, so the only safe action we can take is to call wakeup to break out of the poll loop.
Another thread calling wakeup will cause poll to throw a WakeupException. You’ll want to catch the exception to make sure your application doesn’t exit unexpect‐ edly, but there is no need to do anything with it.
Before exiting the consumer, make sure you close it cleanly.
full example at:
https://github.com/gwenshap/kafka-examples/blob/master/SimpleMovingAvg/src/main/java/com/shapira/examples/newconsumer/simplemovingavg/SimpleMovingAvgNewConsumer.java

How can I support cancellation of a long running masstransit consumer task when the containing topshelf windows service is stopped

I'm using a topshelf windows service to host a masstransit message consumer. One of the consumer tasks can take up to 30 minutes, but is easily interrupted and restarted. When I manually stop the service I would like the consumer task to stop gracefully as soon as possible and to cause masstransit to return the message to the queue where it came from.
I now have this working with a CancellationToken that causes the long running task to throw a TaskCanceledException. In the bus configuration I use the retry configuration to wait until the process is finally killed, thus returning the message to the queue. Is there a better way to implement this? I now get an exception logged by mass transit, and my service doesn't stop as quickly as it should because it is waiting for the Thread.Sleep.
In the long running consumer
if (this.cancellationToken.IsCancellationRequested)
{
throw new TaskCanceledException("manual cancel");
}
The retry code in the bus configuration
var busControl = Bus.Factory.CreateUsingRabbitMq(sbc =>
{
sbc.UseRetry(x =>
{
x.Intervals(this.busConfiguration.RetryIntervals);
x.Ignore<Exception>(ex =>
{
if (cancellationTokenSource.IsCancellationRequested)
{
this.loggingService.LogWarning("Worker stopped manually, messages in progress have been returned to the queue.");
// Wait for process to end, this is not great because this causes mass transit to log an error
Thread.Sleep(TimeSpan.FromDays(1));
}
return false;
});
});
}
When the service is stopped
public virtual void Stop()
{
this.cancellationTokenSource.Cancel();
this.busHandle.Stop();
}

finally is not executed when calling Thread.Abort

Does anyone know a reason why finally statement wouldn't be executed when calling Thread.Abort? I have thread function like this:
void ThreadFunc()
{
try
{
int counter = 0;
while (true)
{
Debug.Log ("Waiting" + counter);
Thread.Sleep(100);
++counter;
}
Debug.Log("Success.");
}
catch(ThreadAbortException ex)
{
Debug.LogWarning("Cancelled: " + ex);
}
catch(System.Exception ex)
{
Debug.LogError("Error: " + ex);
}
finally
{
Debug.Log("Finally");
}
}
I terminate this thread using Thread.Abort. All I see in output is a bunch of Waiting, but no other lines. My main thread keeps running after calling Thread.Abort (i.e. child thread has enough time to complete). Debug.Log functions are thread safe.
This happens on Windows. I'm using Mono (Unity game engine). On Mac it works fine. On iOS I get this behavior, but it seems to depend on device/iOS version or XCode version (I haven't figured out yet). On Windows it happens every time.
BTW: on iOS it crashes if I put another try {} catch {} into finally statement.
Is anyone aware why this is happening? It seems to be quite different from what the documentation of Thread.Abort and ThreadAbortException says.
Mono does not support Constrained Execution Regions and does not fully support catch/finally when Thread.Abort is called.
There is a bug about this.

Windows service stops if there was an exception

I developed Windows service that is using System.Threading.Timer. Timer is starting every x minutes and it works fine (timer is updatet at the end of method). But, if there is an error in try block service just stops despite the fact that I'm updating timer and telling him when to start again
why is that happening? Here is code :
System.Threading.Timer serviceTimer;
protected override void OnStart(string[] args)
{
TimeSpan diff;
diff = nextRun - now;
TimerCallback timerDelegate =
new TimerCallback(MyTimerCallback);
serviceTimer = new System.Threading.Timer(timerDelegate, null,
diff, new TimeSpan(-1));
}
public void MyTimerCallback(object something)
{
try
{
//possible error that happened
}
catch(Exception)
{
}
finally
{
//diff is a new variable telling timer when to start again
serviceTimer.Change(diff, new TimeSpan(-1));
}
}
what am I missing why service stops if there was an error?
Maybe the timer wasn't able to change. Timer.Change returns a boolean:
true if the timer was successfully updated; otherwise, false.
But you're not checking that result. I'd recommend probably disposing the timer and newing up a new one each time, since it's already fired and you created it as a "one shot" timer, e.g.
finally
{
serviceTimer.Dispose();
serviceTimer = new System.Threading.Timer(timerDelegate, null,
diff, new TimeSpan(-1));
}
In case that someone deals with same problem I figured something like this:
Since I want my service to stay alive no matter what :
I 'm reporting to the service manager that the service has successfully started -
base.OnStart(args);
In configuration you can set legacyUnhandledExceptionPolicy set to true (1)

Resources