Stopping a Windows Service in the event of a critical error - service

I have a Windows Service which basically wraps a task:
public partial class Service : ServiceBase
{
private Task task;
private CancellationTokenSource cancelToken;
public Service()
{
InitializeComponent();
this.task = null;
this.cancelToken = null;
}
protected override void OnStart(string[] args)
{
var svc = new MyServiceTask();
this.cancelToken = new CancellationTokenSource();
this.task = svc.RunAsync(cancelToken.Token);
this.task.ContinueWith(t => this.OnUnhandledException(t.Exception), TaskContinuationOptions.OnlyOnFaulted);
}
protected override void OnStop()
{
if (this.task != null)
{
this.cancelToken.Cancel();
this.task.Wait();
}
}
private void OnUnhandledException(Exception ex)
{
this.EventLog.WriteEntry(string.Format("Unhandled exception: {0}", ex), EventLogEntryType.Error);
this.task = null;
this.Stop();
}
}
As you can see, the service can catch unhandled exceptions. If this happens, the exception is logged and the service is stopped. This has the effect of writing two messages to the event log - one error stating there was an unhandled exception, and another stating that the service was successfully stopped.
This may sound minor, but I'm hoping to be able to suppress the 'successfully stopped' message. I find it misleading - it suggests that the service stopping was a normal occurrence. Is there another way I can force the service to stop itself without this message being logged?

Related

The configured execution strategy 'RetryTransactionExecutionStrategy' does not support user initiated transactions

We wrote our own simple execution strategy to retry saving any data using our DbContext when it runs into a table lock timeout.
public class RetryTransactionExecutionStrategy : DbExecutionStrategy
{
public RetryTransactionExecutionStrategy() : base()
{
}
protected override bool ShouldRetryOn(Exception exception)
{
while (exception != null)
{
if (exception is MySqlException ex
&& ex.Number == 1205) // Deadlock error code
{
return true;
}
exception = exception.InnerException;
}
return false;
}
}
We register it by using the DbConfig class, in the same folder as the context class.
public class DbConfig : DbConfiguration
{
public DbConfig()
{
SetExecutionStrategy(MySqlProviderInvariantName.ProviderName, () => new RetryTransactionExecutionStrategy());
}
}
Now most regular usage of the context will use the retry execution strategy. However, transactions are a more special case. Microsoft mentions usage of them in their documentation, and tells the user to manually call the execution strategy, like this:
var executionStrategy = new RetryTransactionExecutionStrategy();
executionStrategy.Execute(() =>
{
using (PigDbAccountEntities pigDbAccountEntities = new PigDbAccountEntities())
{
using (var dbtransaction = pigDbAccountEntities.Database.BeginTransaction())
{
try
{
//work on some data
pigDbAccountEntities.SaveChanges();
//work on some more data
pigDbAccountEntities.SaveChanges();
//work on even more data
pigDbAccountEntities.SaveChanges();
dbtransaction.Commit();
isSaved = true;
}
catch (Exception ex)
{
dbtransaction.Rollback();
Logger.Instance.Log(LogLevel.ERROR, LogSource.DB, "error in AccountEntityManager.SaveApplicationUser", ex);
}
}
}
});
And yet we still get this error message:
The configured execution strategy 'RetryTransactionExecutionStrategy' does not support user initiated transactions. See http://go.microsoft.com/fwlink/?LinkId=309381 for additional information.
Any idea on what to do/check?

Rollout is not being executed when triggered through a custom workflow

We have custom workflow which has a process step to trigger rollout [Standard Rollout]. The process step is completing successful but with no rollout performed.
#Component(
service = WorkflowProcess.class,
property = {
"service.description=Workflow description",
"service.vendor=Project",
"process.label=Project"
}
)
public class RolloutProcessStep implements WorkflowProcess {
private static final Logger LOG = LoggerFactory.getLogger(RolloutProcessStep.class);
#Reference
private ResourceResolverFactory resourceResolverFactory;
#Reference
private RolloutManager rolloutManager;
public void execute(WorkItem item, WorkflowSession workflowSession, MetaDataMap args) throws WorkflowException {
try (ResourceResolver resolver = resourceResolverFactory.getServiceResourceResolver(Collections.singletonMap(
ResourceResolverFactory.SUBSERVICE, RolloutProcessStep.class.getName()))) {
triggerRollout(path, resolver);
} catch (LoginException e) {
LOG.error("Error in getting the resolver. Aborting.", e);
throw new WorkflowException("Error in getting the resolver.");
} catch (Exception e) {
LOG.error("Error in during the step. Aborting.", e);
throw new WorkflowException("Error in during the Rollout Process Step.");
}
}
private void triggerRollout(String path, ResourceResolver resolver) {
Resource source = resolver.getResource(path);
if (source == null) {
return;
}
try {
LiveRelationshipManager relationshipManager = resolver.adaptTo(LiveRelationshipManager.class);
PageManager pageManager = resolver.adaptTo(PageManager.class);
// Checks if the given source is the source of a Live Copy relationship.
if (!relationshipManager.isSource(source)) {
LOG.warn("Resource Not a valid source {}.", source);
return;
}
Page page = pageManager.getPage(source.getPath());
if (page == null) {
LOG.warn("Failed to resolve source page {}.", source);
}
final RolloutManager.RolloutParams params = new RolloutManager.RolloutParams();
params.master = page;
params.isDeep = false;
params.reset = false;
params.trigger = RolloutManager.Trigger.ROLLOUT;
LOG.info("RolloutParams {}.", params.toString());
rolloutManager.rollout(params);
} catch (WCMException e) {
LOG.error("Failed to get live relationships.", e);
}
}
}
PS: We have the blueprints configured already and rollouts performed using touch UI is working as expected.
Please let me know if I'm missing anything.
Issue was resolved by providing permission to the service user to access this Process Step.

Netty Server connection with SSL drops client connection after invocation

I am running Netty 4.2 socket communication code with ssl (self signed certificate).
My Problem:
When client tries to connect to server with SSL, server immediately drops the connection. Server triggers channelUnregistered() method immediately.
One point I noticed is, very first time once the server started, client connection holds and works fine. But when client disconnects and try to connect to Server again, it drops the connection immediately.
But without SSL it works fine without any issues.
Client Code:
public Channel initializeNettySocket()
{
group = new NioEventLoopGroup();
try
{
ClientAdapterInitializer clientAdapterInitializer = null;
if (ServerSettings.isUseSSL())
{
// SSLEngine engine = SSLContextFactory.getClientContext().createSSLEngine();
SSLEngine engine = SSLContext.getDefault().createSSLEngine(host,port);
engine.setUseClientMode(true);
clientAdapterInitializer = new ClientAdapterInitializer(engine);
}
else
{
clientAdapterInitializer = new ClientAdapterInitializer();
}
Bootstrap bootstrap = new Bootstrap().group(group).channel(NioSocketChannel.class).handler(clientAdapterInitializer);
channel = bootstrap.connect(host,port).sync().channel();
Thread.sleep(3000);
setChannel(channel);
}
catch (Exception e)
{
System.out.println(e.getMessage());
e.printStackTrace();
}
return channel;
}
public class ClientAdapterInitializer extends ChannelInitializer<SocketChannel>
{
private SSLEngine sslCtx = null;
public ClientAdapterInitializer(SSLEngine sslCtx)
{
this.sslCtx = sslCtx;
}
public ClientAdapterInitializer()
{
}
#Override
protected void initChannel(SocketChannel channel) throws Exception
{
ChannelPipeline pipeline = channel.pipeline();
if (ServerSettings.isUseSSL())
{
// Add SSL handler first to encrypt and decrypt everything.
// In this example, we use a bogus certificate in the server side
// and accept any invalid certificates in the client side.
// You will need something more complicated to identify both
// and server in the real world.
//pipeline.addLast(sslCtx.newHandler(ch.alloc(), SecureChatClient.HOST, SecureChatClient.PORT));
pipeline.addLast(new SslHandler(sslCtx));
}
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", new ClientAdapterHandler());
}
Server side code
public class ServerAdapterInitializer extends ChannelInitializer<SocketChannel>
{
private SSLEngine sslEngine;
public ServerAdapterInitializer(SSLEngine sslEngine)
{
this.sslEngine = sslEngine;
}
public ServerAdapterInitializer()
{
}
#Override
protected void initChannel(SocketChannel channel) throws Exception
{
ChannelPipeline pipeline = channel.pipeline();
if (sslEngine != null)
{
pipeline.addLast(new SslHandler(sslEngine));
}
Listeners.getInstance().getAllListeners().size();
RTReceiverAdapterHandler rtReceiverAdapterHandler = new RTReceiverAdapterHandler();
pipeline.addLast("idleStateHandler", new IdleStateHandler(0, 0, 10)); // add
// with
// name
pipeline.addLast("decoder", new MyStringDecoder(rtReceiverAdapterHandler));
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", rtReceiverAdapterHandler);
}
}
public class RTReceiverAdapterHandler extends ChannelInboundHandlerAdapter
{
#Override
public void channelActive(ChannelHandlerContext ctx) throws Exception
{
if (ServerSettings.isUseSSL())
{
// Once session is secured, send a greeting and register the channel
// to the global channel
// list so the channel received the messages from others.
ctx.pipeline().get(SslHandler.class).handshakeFuture().addListener(new GenericFutureListener<Future<Channel>>()
{
#Override
public void operationComplete(Future<Channel> future) throws Exception
{
ctx.writeAndFlush("Welcome!\n");
ctx.writeAndFlush("Your session is protected by " + ctx.pipeline().get(SslHandler.class).engine().getSession().getCipherSuite()
+ " cipher suite.\n");
channels.add(ctx.channel());
}
});
}
else
{
super.channelActive(ctx);
}
}
}
The problem was not with the code at all. We have nginx web server configured with SSL before my application. This entry in nginx 'ssl_ciphers AES256+EECDH:AES256+EDH:!aNULL;' was the culprit which was not allowing to access the netty server.
I commented the above entry in ngnix and my problem was resolved.

rxjava: queue scheduler with default idle job

I have a client server application and I'm using rxjava to do server requests from the client. The client should only do one request at a time so I intent to use a thread queue scheduler similar to the trampoline scheduler.
Now I try to implement a mechanism to watch changes on the server. Therefore I send a long living request that blocks until the server has some changes and sends back the result (long pull).
This long pull request should only run when the job queue is idle. I'm looking for a way to automatically stop the watch request when a regular request is scheduled and start it again when the queue becomes empty. I thought about modifying the trampoline scheduler to get this behavior but I have the feeling that this is a common problem and there might be an easier solution?
You can hold onto the Subscription returned by scheduling the long poll task, unsubscribe it if the queue becomes non-empty and re-schedule if the queue becomes empty.
Edit: here is an example with the basic ExecutorScheduler:
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
public class IdleScheduling {
static final class TaskQueue {
final ExecutorService executor;
final AtomicReference<Future<?>> idleFuture;
final Runnable idleRunnable;
final AtomicInteger wip;
public TaskQueue(Runnable idleRunnable) {
this.executor = Executors.newFixedThreadPool(1);
this.idleRunnable = idleRunnable;
this.idleFuture = new AtomicReference<>();
this.wip = new AtomicInteger();
this.idleFuture.set(executor.submit(idleRunnable));
}
public void shutdownNow() {
executor.shutdownNow();
}
public Future<?> enqueue(Runnable task) {
if (wip.getAndIncrement() == 0) {
idleFuture.get().cancel(true);
}
return executor.submit(() -> {
task.run();
if (wip.decrementAndGet() == 0) {
startIdle();
}
});
}
void startIdle() {
idleFuture.set(executor.submit(idleRunnable));
}
}
public static void main(String[] args) throws Exception {
TaskQueue tq = new TaskQueue(() -> {
while (!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
System.out.println("Idle interrupted...");
return;
}
System.out.println("Idle...");
}
});
try {
Thread.sleep(1500);
tq.enqueue(() -> System.out.println("Work 1"));
Thread.sleep(500);
tq.enqueue(() -> {
System.out.println("Work 2");
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
}
});
tq.enqueue(() -> System.out.println("Work 3"));
Thread.sleep(1500);
} finally {
tq.shutdownNow();
}
}
}

MVC 2.0 - Custom handling of all errors to return json

I have an MVC 2 app that I want all requests to return json. I have overridden a HandleErrorAttribute and an AuthorizeAttribute. My goal is that all errors (even 403 and 404) are returned as json.
Here is my error handler. ExceptionModel is a simple class defining any error returned by my application. The Exception handler is a class that translates the error details into a formatted e-mail and sends it to me.
public class HandleErrorJsonAttribute : System.Web.Mvc.HandleErrorAttribute
{
public override void OnException(ExceptionContext context)
{
context.ExceptionHandled = true;
RaiseErrorSignal(context.Exception);
context.RequestContext.HttpContext.Response.ContentType = "application/json";
JsonSerializer serializer = new JsonSerializer();
serializer.Serialize(context.HttpContext.Response.Output, new ExceptionModel(context.Exception));
}
private static void RaiseErrorSignal(Exception ex)
{
IExceptionHandler handler = Resolve();
handler.HandleError(ex.GetBaseException());
}
private static IExceptionHandler Resolve()
{
return ServiceLocator.Locate<IExceptionHandler>();
}
}
Here is the Exception model for clarification
public class ExceptionModel
{
public int ErrorCode { get; set; }
public string Message { get; set; }
public ExceptionModel() : this(null)
{
}
public ExceptionModel(Exception exception)
{
ErrorCode = 500;
Message = "An unknown error ocurred";
if (exception != null)
{
if (exception is HttpException)
ErrorCode = ((HttpException)exception).GetHttpCode();
Message = exception.Message;
}
}
public ExceptionModel(int errorCode, string message)
{
ErrorCode = errorCode;
Message = message;
}
}
and finally, my custom authorize attribute. I an using forms auth, but I did not want any of the automatic redirection. I simply want the error to show on the screen and stop any further processing.
public class AuthorizeTokenAttribute : System.Web.Mvc.AuthorizeAttribute
{
public bool SuperAdminOnly { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool authorized = base.AuthorizeCore(httpContext);
if(!SuperAdminOnly)
return authorized;
if(!authorized)
return authorized;
return SessionHelper.UserIsSuperAdmin(httpContext.User.Identity.Name);
}
protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)
{
throw new HttpException(403, "Access Denied");
}
}
This all works great for most errors, but it is missing one thing. I have a controller action like this.
[AuthorizeToken]
[HttpPost]
public JsonResult MyAction()
{
return new JsonResult();
}
It works fine when you submit via post, but on a get I receive an unhandled 404 error.
Server Error in '/' Application.
The resource cannot be found.
Description: HTTP 404. The resource
you are looking for (or one of its
dependencies) could have been removed,
had its name changed, or is
temporarily unavailable. Please
review the following URL and make sure
that it is spelled correctly.
Requested URL: /MyController/MyAction
Version Information: Microsoft .NET
Framework Version:4.0.30319; ASP.NET
Version:4.0.30319.1
This happens on a GET, which is to be expected as default behavior. However, how can I handle for this condition so that I could instead return json like this
{"ErrorCode":404,"Message":"Page Not Found"}
To handle errors personally I prefer the Application_Error event in Global.asax:
protected void Application_Error(object sender, EventArgs e)
{
var exception = Server.GetLastError();
Response.Clear();
Server.ClearError();
var httpException = exception as HttpException;
var routeData = new RouteData();
routeData.Values["controller"] = "Errors";
routeData.Values["action"] = "Index";
routeData.Values["error"] = exception;
IController errorController = new ErrorsController();
errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}
and then have an ErrorsController:
public class ErrorsController : Controller
{
public ActionResult Index(Exception exception)
{
var errorCode = 500;
var httpException = exception as HttpException;
if (httpException != null)
{
errorCode = httpException.ErrorCode;
}
return Json(new
{
ErrorCode = errorCode,
Message = exception.Message
}, JsonRequestBehavior.AllowGet);
}
}