Why Stop method is invoked many times in Topshelf - windows-services

Topshelf is working as the windows service broker in our application. This morning, we find that the Stop mehtod is invoked many times. Here is the related code.
class Program
{
static void Main(string[] args)
{
ILog Log = new FileLog();
try
{
HostFactory.Run(serviceConfig =>
{
serviceConfig.Service<ServiceManager>(serviceInstance =>
{
serviceInstance.ConstructUsing(() => new ServiceManager());
serviceInstance.WhenStarted(execute => execute.Start());
serviceInstance.WhenStopped(execute => execute.Stop());
});
});
}
catch (Exception ex)
{
Console.WriteLine(ex);
Log.Error("Program.Main", ex, LogType.Error);
Console.ReadLine();
};
}
}
In the ServiceManager, we have the Stop mehtod, which will be invoked then TopShelf receives the stop signal from operation system.
class ServiceManager
{
xxx.....
public bool Stop()
{
try
{
_log.Info("The service is stopping", LogType.Info);
_service.StopExecuteProduceMessage();
Task.WaitAll(_tasks.ToArray());
_log.Info("The service is stopped", LogType.Info);
}
catch (Exception ex)
{
_log.Error("Stop", ex, LogType.Error);
}
return true;
}
}
This morning, we find the service is stopped with unclear reason. And there are many lines logging about this stop action.
I guess Topshelf invoke ServiceManager.Stop method many times. Anyone have encountered this problem before? I want to know I can trace why this happens.
Anyone can help? Many thanks.

You are experiencing this behavior because your Stop() method takes a while but is not being responsive to the request to stop.
Your method essentially looks like this:
Stop() {
log-stopping;
wait-a-while;
log-stopped;
}
While you are waiting, the status of the service remains "Running". This causes the requester (could be Windows itself or another program) to keep re-sending the stop request, resulting in multiple parallel/overlapping calls to Stop(). That accounts for the first 10 lines in the log you included.
You can see that it takes almost 20 seconds for the "wait" to complete (from 05:39:45 to 05:40:04).
After that, it looks like Topshelf may be stuck. That causes more messages to be sent. (Notice that in the next lines in your log, the stopping and starting pairs are logged simultaneously because your tasks are stopped and there is no waiting).
To fix the problem, you should:
Modify your WhenStopped() call to pass the HostControl parameter to Stop():
serviceInstance.WhenStopped((execute, hostControl) => execute.Stop(hostControl));
Update the Stop() method to take the HostControl parameter and make this call before the call to Task.WaitAll():
hostControl.RequestAdditionalTime(TimeSpan.FromSeconds(30));
This will inform Windows that your service has received the request and may be working on it for up to 30 seconds. That should avoid the repeated calls.
Reference: Topshelf documentation

Related

Quit a specflow scenario, or avoid execution based on a precondition

I want to be able to avoid a specflow scenario execution, or quit at the first step, depending on external configuration. Is that possible?
Like
Background:
Given we have a satisfied precondition
the precondition fails and the scenario stops without returning an error
IUnitTestRuntimeProvider interface should be injected
https://docs.specflow.org/projects/specflow/en/latest/Execution/SkippingScenarios.html
however, I then run into the fact that this interface can not be resolved
https://github.com/SpecFlowOSS/SpecFlow/issues/2076
the resolution of this does not work for me in a .Net 5, XUnit project, with Visual Studio 2019
If a step does not throw an exception, then the step passes. You could refactor that particular step into a private method, then simply wrap the method call in a try-catch inside an if statement:
[Given(#"we have a satisfied precondition")]
public void GivenWeHaveASatisfiedPrecondition()
{
if (/* check your external config here */)
{
try
{
PerformPrecondition();
}
catch (Exception ex)
{
Console.WriteLine("Step failed, but continuing scenario." + Environment.NewLine + Environment.NewLine + ex);
}
}
else
{
// Failure in this step should fail the scenario.
PerformPrecondition();
}
}
private void PerformPrecondition()
{
// Your step logic goes here
}
You haven't specified where your external configuration is at, but there are a thousand ways to do this.

How to simulate long time process (sleep) in Dart?

I want to stop/sleep executing to simulate long time process, unfortunately I can't find information about it. I've read the following topic (How can I "sleep" a Dart program), but it isn't what I look for.
For example sleep() function from dart:io packages isn't applicable, because this package is not available in a browser.
For example:
import 'dart:html';
main() {
// I want to "sleep"/hang executing during several seconds
// and only then run the rest of function's body
querySelect('#loading').remove();
...other functions and actions...
}
I know that there is Timer class to make callbacks after some time, but still it doesn't prevent the execution of program as a whole.
There is no way to stop execution. You can either use a Timer, Future.delayed, or just use an endless loop which only ends after certain time has passed.
If you want a stop the world sleeping function, you could do it entirely yourself. I will mention that I don't recommend you do this, it's a very bad idea to stop the world, but if you really want it:
void sleep(Duration duration) {
var ms = duration.inMilliseconds;
var start = new DateTime.now().millisecondsSinceEpoch;
while (true) {
var current = new DateTime.now().millisecondsSinceEpoch;
if (current - start >= ms) {
break;
}
}
}
void main() {
print("Begin.");
sleep(new Duration(seconds: 2));
print("End.");
}

Calling build.doStop() in prebuild is not stopping fast enough

I am trying to write a Jenkins plugin that can automatically abort a build if that build is triggered on a holiday (or just a given input day/s). The user can configure the days, and each job gets a checkbox that allows the user to decide if they want their job aborted on a holiday or not. Currently my plugin extends JobProperty and utilizes global configuration where I have a list of blacklisted dates. If today is on my list of blacklisted days, then I do not want my job to run. The plugin "works" but with a few annoying caveats.
My main issue is that I can only FAIL the build if it happens to be triggered on a day that's one of my blacklisted days. This is a problem for me because there's no actual error. The job is operating as it should be and I don't want to receive emails full of errors just because the job was halted on a day I didn't want it to run (e.g: a holiday)
When my plugin decides to abort a build, I want to be able to end the job with an "Aborted" status. (In fact - I'd like to be able to control the status and leave it as a potential parameter.)
Below is my prebuild() code.
#Override
public boolean prebuild(AbstractBuild build, BuildListener listener) {
boolean stopped = false;
if(checkIfClosed) {
LocalDate today = LocalDate.now();
listener.getLogger().println("Checking the date for " + DateFormats.yyyyMMdd.print(today));
if (getDescriptor().getUseCalculatedDateChecker()) {
if (!NyseHolidayChecker.isMarketOpen(today)) {
listener.getLogger().println("Closed (From auto calculation)!");
stopped = true;
}
}
if (getDescriptor().getListOfClosedDates() != null && !getDescriptor().getListOfClosedDates().isEmpty()) {
if (getDescriptor().getListOfClosedDates().contains(DateFormats.yyyyMMdd.print(today))) {
listener.getLogger().println("Closed. Date is in the Closed Date List. " +
"If this is wrong check global configuration.");
stopped = true;
}
}
}
if(stopped) {
try {
if(build.doStop() == null) {
return false;
}
} catch (IOException e) {
listener.getLogger().println(e.getMessage());
return false;
} catch (ServletException e) {
listener.getLogger().println(e.getMessage());
return false;
}
//throw new RuntimeException("This job has been told not to run when marked as Closed!");
//throw new AbortException("This job has been told not to run when marked as Closed!");
}
return true;
}
I've tried several different ways to get the job to abort immediately and not have the build marked as failed.
The doc tells me that I should throw an AbortException but that does not appear to be supported by the function I'm overriding.
I also tried to call doStop() but then my first build step (out of 2) still runs at least a little. This isn't desirable because I will never know what state my job will be in when it will be aborted (it could have already sshed somewhere and killed a process...or made something live etc)
What am I missing? I feel like I'm hacking around to get what I need. I am hoping someone can point me in the right direction on how to best do this.
Digging further into Jenkins code showed the Build.doRun() method will execute the build steps in a do while loop which was allowing for a small bit of the build step to get through. The AbortException which Jenkins documentation recommends will also mark a build as failure (undesirable). The only means I found to cancel a job and have it properly mark as just aborted was to throw an InterruptedException. The JobProperties prebuild() function does not allow for any throws (other than Runtime which will mark as failure).
The plugin now extends BuildWrapper. This has both a setUp and preCheckout method that will run prior to build steps executing. These two methods can also throw InterruptedExceptions. Now if my checks pass and the date is blacklisted an InterruptedException is thrown from the interruptOnHoliday(...) method. The BuildWrapper also utilizes a BuildWrapperDescriptor which will place a checkbox in the job configuration based on the name provided in the overridden getDisplayName() function (Acts sort of as a jetty optionalBlock). With this box checked the setUp function can get called, otherwise it will not. This effectively makes the holiday check plugin optional (desired).
To give help to a user on what the Plugin does, include a help.html file in the resources for the plugin, this will allow the programmer to explain to the user how and why to use the Plugin. The BuildWrapperDescriptor class will programmatically know how to use that file.
Hope this helps everyone. Below is the new way to kill :
#Override
public void preCheckout(AbstractBuild build, Launcher launcher, BuildListener listener)
throws InterruptedException, IOException {
interruptOnHoliday(build, listener);
}
/**
* Run a check against todays date and dates from the {#link NyseHolidayChecker}
* which is an automatic calculator for New York Stock Exchange holidays and also a check against the manually
* created user date list. If either one is not checked to be used, then they will be ignored.
*
* #param build {#link hudson.model.AbstractBuild} that we are on, will kill the executor
* #param listener {#link hudson.model.BuildListener} that we will log to
*
* #throws InterruptedException
*/
private void interruptOnHoliday(AbstractBuild build, BuildListener listener) throws InterruptedException {
boolean stopped = false;
LocalDate today = LocalDate.now();
listener.getLogger().println("Checking the date for " + DateFormats.yyyyMMdd.print(today));
//if the NYSE calculator is checked then let's use it
if (getDescriptor().getUseNyseCalculatedDateChecker()) {
if (!NyseHolidayChecker.isMarketOpen(today)) {
listener.getLogger().println("The NYSE is not Open today (From auto calculation)" +
" and this job is marked to abort. Stopping the build!");
stopped = true;
}
}
//If we have inserted manual dates into the list we want to check them
if (getDescriptor().getListOfClosedDates() != null && !getDescriptor().getListOfClosedDates().isEmpty()) {
if (getDescriptor().getListOfClosedDates().contains(DateFormats.yyyyMMdd.print(today))) {
listener.getLogger().println("This date is blacklisted, and this job is marked to abort. " +
"Stopping the job! If this date should not be on the list check Jenkins Settings.");
stopped = true;
}
}
//if we should stop the job then we call doStop() on the build and we also throw an InterruptedException
//The InterruptedException is the only way to abort a build without it failing.
if (stopped) {
try {
build.doStop();
throw new InterruptedException(DateFormats.yyyyMMdd.print(today) + " is a blacklisted date.");
} catch (IOException e) {
listener.getLogger().println(e.getMessage());
} catch (ServletException e) {
listener.getLogger().println(e.getMessage());
}
}
}
#Override
public BuildWrapper.Environment setUp(AbstractBuild build, Launcher launcher, BuildListener listener)
throws InterruptedException, IOException {
interruptOnHoliday(build, listener);
return new CloseCheckerEnvironment();
}

Dart isolate call or send

I have a couple questions about how isolate works :
1) What is the difference between call and send and when I should use call over send?
2) Just curiosity, is there any way to chain isolate like we chain Future ?
3)
import 'dart:isolate';
echo() {
port.receive((msg, reply) {
print('I received: $msg');
});
}
main() {
var sendPort = spawnFunction(echo);
sendPort.call('Hello from main');
}
It displays : I received: Hello from main
but when I use send, it prints nothing, why?
Use the call() method on SendPort as a simple way to send a message and receive a reply. The call() method returns a Future for the reply. If you don't bother of the reply and simply want to send a message, use send().
Have a look at dart:isolate - Concurrency with Isolates for more informations.
For 3) it's explained in the above link :
In the standalone VM, the main() function runs in the first isolate (also known as the root isolate). When the root isolate terminates, it terminates the whole VM, regardless of whether other isolates are still running. For more information, see the section called “Keeping the root isolate alive”.

Timer job not listed in Timer Job Definitions + Sharepoint 2007

I have created a Custom Timer job which is added when a feature gets activated. The feature does get activated without any exception. But the timer job is not being listed in Timer Job definitions on Central Admin.
The same is working on Staging Server but I am facing this in Production Server.
I am working on Sharepoint2007.
Below is what I have done in Feature Activated.
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
try
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
SPWeb parentWeb = properties.Feature.Parent as SPWeb;
UpdateEmpReferralListTimer taskJob;
SPMinuteSchedule schedule;
foreach (SPJobDefinition job in parentWeb.Site.WebApplication.JobDefinitions)
{
if (job.Name == "xyz")
job.Delete();
}
parentWeb = properties.Feature.Parent as SPWeb;
taskJob = new UpdateEmpReferralListTimer("xyz", parentWeb.Site.WebApplication);
schedule = new SPMinuteSchedule();
schedule.BeginSecond = 0;
schedule.EndSecond = 59;
taskJob.Schedule = schedule;
taskJob.Update();
});
}
catch (Exception Ex)
{
string str = Ex.Message.ToString();
}
}
Scope of Feature is "Web"
To my knowledge trying to perform tasks that require administrator privilegies (like creating timer job) should not work from site level feature activation callback if SharePoint accounts set up properly. Account that web sites run under normally does not have adminstrative privilegies.
It likely works on your staging server due to all accounts having the same privileges. Check out SharePoint logs on your production server to see what exception is (after removing code that eats exception without rethrowing/reporting it - catch (Exception Ex) {...}).
how do you know that your feature is getting activated without error. your code has try/catch block and you are doing nothing in catch block. if your code throwing any error, your catch block will suppress it.
add this line in your catch block and check sharepoint log.
Microsoft.SharePoint.Administration.SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("Development Debugging", TraceSeverity.Unexpected, EventSeverity.Information), TraceSeverity.Unexpected, str, null);
you can find log files in C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\LOGS folder

Resources