Quartz.Net Jobs in Azure WebRole - azure

I'm currently porting a WCF Service Project over to an Azure Role. Until now the library containing the service also hosted a Quartz.Net JobFactory for some lightweight background processing (perdiodically cleaning up stale email confirmation tokens). Do I have to move that code into a seperate worker role?

No you don't have to setup a separate worker role.
You simply have to start a background thread in your OnStart() Method of your Web Role. Give that thread a Timer object that executes your method after the given timespan.
Due to this you can avoid a new worker role.
class MyWorkerThread
{
private Timer timer { get; set; }
public ManualResetEvent WaitHandle { get; private set; }
private void DoWork(object state)
{
// Do something
}
public void Start()
{
// Execute the timer every 60 minutes
WaitHandle = new ManualResetEvent(false);
timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromMinutes(60));
// Wait for the end
WaitHandle.WaitOne();
}
}
class WebRole : RoleEntryPoint
{
private MyWorkerThread workerThread;
public void OnStart()
{
workerThread = new MyWorkerThread();
Thread thread = new Thread(workerThread.Start);
thread.Start();
}
public void OnEnd()
{
// End the thread
workerThread.WaitHandle.Set();
}
}

The answer above helped me a lot, but it has one hickup, the OnStart method is not overwritten so the method is never called. Also it should be Boolean and not void. This worked for me:
public override bool OnStart()
{
// For information on handling configuration changes
// see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.
workerThread = new MyWorkerThread();
Thread thread = new Thread(workerThread.Start);
thread.Start();
return base.OnStart();
}

Related

how to do something when liferay module stop

i am making cron job like loop to do something using new thread.
when module stop, this thread keeps running, so when i deployed updated module, i'm afraid it will make duplicate thread doing similar task
#Component(immediate = true, service = ExportImportLifecycleListener.class)
public class StaticUtils extends Utils{
private StaticUtils() {}
private static class SingletonHelper{
private static final StaticUtils INSTANCE = new StaticUtils();
}
public static StaticUtils getInstance() {
return SingletonHelper.INSTANCE;
}
}
public class Utils extends BaseExportImportLifecycleListener{
public Utils() {
startTask();
}
protected Boolean CRON_START = true;
private void startTask() {
new Thread(new Runnable() {
public void run() {
while (CRON_START) {
System.out.println("test naon bae lah ");
}
}
}).start();
}
#Deactivate
protected void deactivate() {
CRON_START = false;
System.out.println(
"cron stop lah woooooooooooooooooy");
}
}
i'm using liferay 7
I have populated task that i store from db, so this thread is checking is there a task that it must do, then if it exist execute it.
I'm quite new in osgi and liferay. i've try to use scheduler and failed and also exportimportlifecycle listener but dont really get it yet
think again: Do you really need something to run all the time in the background, or do you just need some asynchronous processing in the background, when triggered? It might be better to start a background task as a one-off, that automatically terminates
Liferay provides an internal MessageBus, that you can utilize to listen to events and implement background processing, without the need for a custom thread
You're in the OSGi world, so you can utilize #Activate, #Modified, #Deactivate (from org.osgi.service.component.annotations) or use a org.osgi.framework.BundleActivator.
But, in general, it's preferable if you don't start your own thread

Azure Cloud Service: RoleEnvironment.StatusCheck event not firing

I am maintaining a legacy Cloud Services application hosted on Azure targeting .net 4.6.1. Inside the Application_Start method of the Global.asax on the Web Role we are registering an event handler for RoleEnvironment.StatusCheck however our logs are demonstrating that this event call back is never being called or triggered.
According to this blog: https://convective.wordpress.com/2010/03/18/service-runtime-in-windows-azure/ we were expecting this event to be triggered every 15 seconds and we believe this was happening however has since stopped. We expect that the stopped working around the time we installed some new DLLs into the solution (some of these dlls include: Microsoft.Rest.ClientRuntime.dll, Microsoft.Azure.Storage.Common.dll, Microsoft.Azure.Storage.Blob.dll, Microsoft.Azure.KeyVault.dll)
We've tried RDP-ing onto the VM to check the event logs but nothing obvious is there. Any suggestions on where we may be able to search for clues?
It seems your event handler is not registered. Try below code with a different approach:
public class WorkerRole : RoleEntryPoint
{
public override bool OnStart()
{
RoleEnvironment.StatusCheck += RoleEnvironmentStatusCheck;
return base.OnStart();
}
// Use the busy object to indicate that the status of the role instance must be Busy
private volatile bool busy = true;
private void RoleEnvironmentStatusCheck(object sender, RoleInstanceStatusCheckEventArgs e)
{
if (this.busy)
{
// Sets the status of the role instance to Busy for a short interval.
// If you want the role instance to remain busy, add code to
// continue to call the SetBusy method
e.SetBusy();
}
}
public override void Run()
{
Trace.TraceInformation("Worker entry point called", "Information");
while (true)
{
Thread.Sleep(10000);
}
}
public override void OnStop()
{
base.OnStop();
}
}

Azure Webjobs and Queues

I am working with an Azure Service Bus Queue (or potentially a topic if required), and would like to know how a Web Job can be used with the Queue.
When a message comes onto the queue it represents a process that will run within the web job (or be started from the webjob). This process might be quick, 30 seconds, or it might be slow, 1 hour etc.
Can I use a single Web Job for this and somehow say that it should be running no more than 10 of these processes at a time?
Yes you can use a WebJob. I have created a simple WebJob with Storage Queue to just guide how it can be done. The below workflow will run only ten process at a time and keep all the other requests in memory of ConcurrentQueue. You will have to implement the logic to dequeue it and consume it
public class Functions
{
public delegate void CompletedProcessHandler(object sender, CompletedProcessHandlerArgs args);
static readonly Dictionary<int, CustomProcess> _dictionary =
new Dictionary<int, CustomProcess>();
static readonly ConcurrentQueue<ProcessEntity> _remaining =
new ConcurrentQueue<ProcessEntity>();
// This function will get triggered/executed when a new message is written
// on an Azure Queue called queue.
public static void ProcessQueueMessage([QueueTrigger("testqueue")] ProcessEntity msg,
TextWriter log)
{
if (_dictionary.Count <= 10)
{
var newProcess = new CustomProcess((_dictionary.Last().Key) + 1,
msg.Duration);
}
else
{
_remaining.Enqueue(msg);
}
}
public static void CompletedProcess(object sender, CompletedProcessHandlerArgs args)
{
_dictionary[Int32.Parse(args.ProcessID)].Dispose();
_dictionary.Remove(Int32.Parse(args.ProcessID));
}
}
public class CustomProcess : IDisposable
{
public event Functions.CompletedProcessHandler OnProcessCompleted;
private CancellationTokenSource _token;
private string _id;
private Timer _timer;
public CustomProcess(int i, int duration)
{
_timer = new Timer { Enabled = true, Interval = duration * 1000 };
_timer.Elapsed += Timer_Elapsed;
_id = i.ToString();
_token = new CancellationTokenSource();
Task.Factory.StartNew(() => WriteMessages());
_timer.Start();
OnProcessCompleted += Functions.CompletedProcess;
}
private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
_token.Cancel();
OnProcessCompleted?.Invoke(this, new CompletedProcessHandlerArgs(_id));
}
private void WriteMessages()
{
while (!_token.Token.IsCancellationRequested)
{
Console.WriteLine("Test Message from process " + _id);
}
}
public void Dispose()
{
_token.Dispose();
_timer.Dispose();
}
}
public class CompletedProcessHandlerArgs : EventArgs
{
public string ProcessID { get; set; }
public CompletedProcessHandlerArgs(string ID)
{
ProcessID = ID;
}
}
public class ProcessEntity
{
public int Duration { get; set; }
}
In the app.config of the web job you need to provide the two app settings
<add name="AzureWebJobsDashboard"
connectionString="DefaultEndpointsProtocol=https;AccountName=[AccountName];AccountKey=[AccountKey]" />
<add name="AzureWebJobsStorage"
connectionString="DefaultEndpointsProtocol=https;AccountName=[AccountName];AccountKey=[AccountKey]" />
The Program file is the default one from the Visual Studio template
public class Program
{
// Please set the following connection strings in app.config for this WebJob to run:
// AzureWebJobsDashboard and AzureWebJobsStorage
static void Main()
{
var host = new JobHost();
// The following code ensures that the WebJob will be running continuously
host.RunAndBlock();
}
}
WebJob will keep dequeue the message the moment it comes. Since you want only 10 to run at a time you will have to enqueue the message in memory and wait for running process to complete before you start a new one
As #Rick has mentioned you can set the is_Singleton property to true in settings.job file of the web job
Yes, you can trigger a web job with an Azure Service Bus Queue or Topic. A good example to look at to get you going would be the Service Bus quick start project template in Visual Studio.
In particular, you want to look at the ServiceBusTrigger attribute that the Web Jobs SDK provides.
As for the scalability of the web job, this will scale according to your web app instances. So, if you had say 5 instances of your web app with always on enabled, then you would have 5 instances of your web job. As an additional comment on this, if you wanted just one instance of the web job in an environment of 5 web app instances, then you could set the is_singleton property to true in the settings.job file.

Ninject - In what scope DbContext should get binded when RequestScope is meaningless?

In an MVC / WebAPI environment I would use InRequestScope to bind the DbContext.
However, I am now on a Console application / Windows service / Azure worker role (doesn't really matter, just there's no Web request scope), which periodically creates a number of Tasks that run asynchronously. I would like each task to have its own DbContext, and since tasks run on their own thread, I tried binding DbContext using InThreadScope.
Unfortunately, I realize that the DbContext is not disposed when a task is finished. What actually happens is, the thread returns to the Thread Pool and when it is assigned a new task, it already has a DbContext, so DbContexts stay alive forever.
Is there a way InThreadScope can be used here or should I use some other scope? How can ThreadScope be used when threads are returning from ThreadPool every now and then?
If you decide to go on with custom scope, the solution is:
public sealed class CurrentScope : INotifyWhenDisposed
{
[ThreadStatic]
private static CurrentScope currentScope;
private CurrentScope()
{
}
public static CurrentScope Instance => currentScope ?? (currentScope = new CurrentScope());
public bool IsDisposed { get; private set; }
public event EventHandler Disposed;
public void Dispose()
{
this.IsDisposed = true;
currentScope = null;
if (this.Disposed != null)
{
this.Disposed(this, EventArgs.Empty);
}
}
}
Binding:
Bind<DbContext>().To<MyDbContext>().InScope(c => CurrentScope.Instance)
And finally:
using (CurrentScope.Instance)
{
// your request...
// you'll get always the same DbContext inside of this using block
// DbContext will be disposed after going out of scope of this using block
}

How to implement cancellable worker thread

I'm trying to implement a cancellable worker thread using the new threading constructs in System.Threading.Tasks namespace.
So far I have have come up with this implementation:
public sealed class Scheduler
{
private CancellationTokenSource _cancellationTokenSource;
public System.Threading.Tasks.Task Worker { get; private set; }
public void Start()
{
_cancellationTokenSource = new CancellationTokenSource();
Worker = System.Threading.Tasks.Task.Factory.StartNew(
() => RunTasks(_cancellationTokenSource.Token),
_cancellationTokenSource.Token
);
}
private static void RunTasks(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
Thread.Sleep(1000); // simulate work
}
}
public void Stop()
{
try
{
_cancellationTokenSource.Cancel();
Worker.Wait(_cancellationTokenSource.Token);
}
catch (OperationCanceledException)
{
// OperationCanceledException is expected when a Task is cancelled.
}
}
}
When Stop() returns I expect Worker.Status to be TaskStatus.Canceled.
My unit tests have shown that under certain conditions Worker.Status remains set to TaskStatus.Running.
Is this a correct way to implement a cancellable worker thread?
I believe that the problem is in your call to
Worker.Wait(_cancellationTokenSource.Token);
That's waiting for the token to be signalled - which it already is, because you've just called Cancel(). If you change that to just
Worker.Wait();
then I believe you'll see a state of RanToCompletion. You won't see Canceled, because your task isn't throwing OperationCanceledException. If you change your RunTasks method to call
cancellationToken.ThrowIfCancellationRequested()
at the end, then you'll need to catch an AggregateException in Stop - but then you'll see a state of Canceled at the end.
At least, that's what my experimentation shows :)

Resources