Why quartz.net does not work in the azure web application? - azure

Quartz.net starts when the application starts and does its work (adding records to the database) every 60 seconds, but when I upload it to Azure, it stops performing its work. What could be wrong?
public static async void Start()
{
IScheduler scheduler = await
StdSchedulerFactory.GetDefaultScheduler();
await scheduler.Start();
IJobDetail job = JobBuilder.Create<CurrencyUpdate>().Build();
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger1", "group1")
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInSeconds(60)
.RepeatForever())
.Build();
await scheduler.ScheduleJob(job, trigger);
}

Related

Azure Function - Broadcast a message from an TimerTrigger to an Azure SignalR Service

All I'm hoping to do is Broadcast a message to all say every 5min.
I thought that the below would work but I need a connectionId and a connectionId is readonly.
I have looked at using LogicApps but those have no connector to SignalR. Every single example I've found looks at older, deprecated versions. I'd even happily assign a unique ConnectionId to my service if that was feasible.
[FunctionName("SendMessage")]
public static async Task RunAsync([TimerTrigger("0 */1 * * * *")] TimerInfo myTimer, ILogger log)
{
HubConnection connection = new HubConnectionBuilder()
.WithUrl(new Uri("http://localhost:5003/MessageHub"))
.WithAutomaticReconnect()
.Build();
await connection.StartAsync();
await connection.InvokeAsync("SendMessageToGroup", "Group2", "This is a test");
}
Use this:
var connection = new HubConnectionBuilder()
.WithUrl("http://localhost:5003/messagehub", options =>
{
options.Headers["Application"] = "API Sender";
})
.WithAutomaticReconnect()
.Build();
await connection.StartAsync();
await connection.SendAsync("SendNotification", "test");
In your messagehub.cs, create this:
public async Task SendNotification(string mensagem)
{
await Clients.All.SendAsync("ReceiveGenericEvent", mensagem, DateTime.Now.Ticks.ToString());
}
https://github.com/hgmauri/signalr-socket-dotnet5

How to fetch events from eventhub from a timer enabled azure function?

I am working with Azure Event Hubs. My requirement is to fetch the events from Azure Event Hub, using azure function on a daily basis. Basically my azure function will be timer enabled. It should be able to fetch the data from azure event hubs. Is there a mechanism for this ?
I am aware that we can trigger a azure function whenever an event is received at event hub. This i don't want as the function will execute n number of time. I want to just fetch the events on a daily basis.
You can still create a timer triggered function and create consumer clients in your code to receive events. See sample code below. Let me know if you have any questions.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Azure.Messaging.EventHubs.Consumer;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
namespace FunctionApp7
{
public static class Function1
{
const string EventHubsConnectionString = "your connection string";
const string EventHubName = "evethub name";
const string ConsumerGroupName = "cgname";
[FunctionName("Function1")]
public static void Run([TimerTrigger("0 */5 * * * *")]TimerInfo myTimer, ILogger log)
{
log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
// You better dissover partitions by eventhub client. I am just hardcoding them here for now.
var partitions = new List<string> { "0", "1" };
var receiveTasks = new List<Task>();
foreach(var p in partitions)
{
receiveTasks.Add(ReadEventsFromPartition(p));
}
// Wait until all reads complete.
Task.WhenAll(receiveTasks);
}
public static async Task ReadEventsFromPartition(string partitionId)
{
await using (var consumer = new EventHubConsumerClient(ConsumerGroupName, EventHubsConnectionString, EventHubName))
{
EventPosition startingPosition = EventPosition.FromOffset(CheckpointStore.ReadOffsetForPartition(partitionId));
long lastOffset = -1;
await foreach (PartitionEvent receivedEvent in consumer.ReadEventsFromPartitionAsync(partitionId, startingPosition))
{
// Process received events here.
// Break if no events left.
if (receivedEvent.Data == null)
{
break;
}
lastOffset = receivedEvent.Data.Offset;
}
// Persist last event's offset so we can continue reading from this position next time function is triggered.
if (lastOffset != -1)
{
// Write offset into some durable store.
CheckpointStore.WriteOffsetForPartition(partitionId, lastOffset);
}
}
}
}
}

Azure Durable Function Invoke without HttpTrigger (Autostart)

I am looking at this example to run a durable function Activity after a set timeout.
https://learn.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-eternal-orchestrations
This will allow my function activity to perform processing of data, then wait exactly 1 hour before it attempts to load again. This will continue to run forever. Perfect.
However, when publishing the Function to Azure, I don't want to have to manually invoke/start the function via the associated HTTP Trigger. I just want the durable function to kickoff automatically and start processing.
Is this possible? If not, what is a suggested work around?
Thanks!
As discussed in the comments, one way of doing this would be to add a new Task in your Release pipeline.
Here is what I understood of your setup from your question:
[FunctionName("ClientFunction")]
public static async Task<HttpResponseMessage> OnHttpTriggerAsync([HttpTrigger(AuthorizationLevel.Anonymous, "post")]
HttpRequestMessage request, [OrchestrationClient] DurableOrchestrationClient starter, ILogger logger)
{
// Triggers the orchestrator.
string instanceId = await starter.StartNewAsync("OrchestratorFunction", null);
return new HttpResponseMessage(HttpStatusCode.OK);
}
[FunctionName("OrchestratorFunction")]
public static async Task DoOrchestrationThingsAsync([OrchestrationTrigger] DurableOrchestrationContext context, ILogger logger)
{
DateTime deadline = context.CurrentUtcDateTime.Add(TimeSpan.FromHours(1));
await context.CreateTimer(deadline, CancellationToken.None);
// Triggers some yout activity.
await context.CallActivityAsync("ActivityFunction", null);
}
[FunctionName("ActivityFunction")]
public static Task DoAnAwesomeActivity([ActivityTrigger] DurableActivityContext context)
{
}
Now, every time you deploy a new version of the Function App, you need the orchestrator to be run. However, I do not think it can be started by itself.
What I propose is to have a simple bash script (using curl or something else) that would call the ClientFunction at the appropriate URL.
On top of that, one of the nice things of this solution is that you could make the deployment fail if the Azure Function does not respond.
This seems to be working too.
[FunctionName("AutoStart")]
public static async Task Run([TimerTrigger("*/5 * * * * *", RunOnStartup = true, UseMonitor = false)]TimerInfo myStartTimer,
[DurableClient] IDurableClient orchestrationClient, ILogger log)
{
string instanceId = await orchestrationClient.StartNewAsync("Start_Orchestrator", null);
}
I don't know if there are hidden problems with this, but I'm experimenting now with having a TimerTrigger that runs on startup and also once a day at midnight (or whatever schedule you want). That TimerTrigger will search the list of instances for any running instances of this orchestration, terminate them, then start a new one.
private const string MyOrchestrationName = "MyOrchestration";
[FunctionName("MyOrchestration_Trigger")]
public async Task MyOrchestrationr_Trigger(
[TimerTrigger("0 0 0 * * *", RunOnStartup = true)] TimerInfo timer,
[DurableClient] IDurableOrchestrationClient starter,
ILogger log,
CancellationToken cancellationToken)
{
// Get all the instances currently running that have a status of Pending, Running, ContinuedAsNew
var instances = await starter.ListInstancesAsync(new OrchestrationStatusQueryCondition()
{
ShowInput = false,
RuntimeStatus = new List<OrchestrationRuntimeStatus>() { OrchestrationRuntimeStatus.Suspended, OrchestrationRuntimeStatus.Pending, OrchestrationRuntimeStatus.Running, OrchestrationRuntimeStatus.ContinuedAsNew }
}, cancellationToken);
// Find any instances of the current orchestration that are running.
var myInstances = instances.DurableOrchestrationState.Where(inst => inst.Name == MyOrchestrationName);
List<Task> terminateTasks = new List<Task>();
foreach (var instance in myInstances )
{
// Delete any instances that are currently running.
terminateTasks.Add(starter.TerminateAsync(instance.InstanceId, $"Restarting eternal orchestration"));
}
await Task.WhenAll(terminateTasks);
// Start the new task now that other instances have been terminated.
string instanceId = await starter.StartNewAsync(MyOrchestrationName, null);
log.LogInformation($"Started orchestration with ID = '{instanceId}'.");
}
I think at least for my purposes this will be safe. Any activities that are running when you terminate will still run to completion (which is what I want in my case), so you would just kill it and restart it on a schedule.

c# Quartz how to toggle schedule a job which is designed to run hourly and daily

I am new to Quartz.Net. I have a job which is scheduled to run hourly and daily. Please find below my schedule service details.
Now i want to toggle the schedule so that i can enable or disable the hourly or daily schedule.
public class SchedulerService : ISchedulerService
{
private readonly IScheduler _scheduler;
private readonly IConfigurationReader _configReader;
public SchedulerService(IScheduler scheduler, IConfigurationReader configReader)
{
_scheduler = scheduler;
_configReader = configReader;
}
public void Start()
{
StartScheduledJobs();
}
public void Stop()
{
_scheduler.Shutdown(true);
}
private void StartScheduledJobs()
{
try
{
_scheduler.Start();
if(_configReader.HourlyChangeJobEnabled) //Will this work? or is this the way to achieve this?
ScheduleHourlyChangesJob();
if(_configReader.DailyChangeJobEnabled)
ScheduleDailyChangesJob();
}
catch (Exception ex)
{
_logProvider.Error("", ex);
}
}
private void ScheduleHourlyChangesJob()
{
var jobDetail = JobBuilder.Create<SimpleJob>()
.WithIdentity("hourlyJob", "group1")
.UsingJobData("mode","hourly")
.Build();
var trigger = TriggerBuilder.Create()
.WithIdentity("hourlyTrigger", "group1")
.WithSchedule(CronScheduleBuilder.CronSchedule("0 0 1/1 ? * *")
.Build();
_scheduler.ScheduleJob(jobDetail, trigger);
}
private void ScheduleDailyChangesJob()
{
var jobDetail = JobBuilder.Create<SimpleJob>()
.WithIdentity("dailyJob", "group1")
.UsingJobData("mode", "daily")
.Build();
var trigger = TriggerBuilder.Create()
.WithIdentity("dailyTrigger", "group1")
.WithSchedule(CronScheduleBuilder.CronSchedule("0 0 0 1/1 * ?"))
.Build();
_scheduler.ScheduleJob(jobDetail, trigger);
}
}
Can anyone help me how to achieve this?
Thanks
It looks like your code will enable the new trigger but does not remove the old trigger. The following code is an example on changing triggers taken from http://www.quartz-scheduler.org/documentation/quartz-2.x/cookbook/UpdateTrigger.html
// retrieve the trigger
Trigger oldTrigger = sched.getTrigger(triggerKey("oldTrigger", "group1");
// obtain a builder that would produce the trigger
TriggerBuilder tb = oldTrigger.getTriggerBuilder();
// update the schedule associated with the builder, and build the new trigger
// (other builder methods could be called, to change the trigger in any desired way)
Trigger newTrigger = tb.withSchedule(simpleSchedule()
.withIntervalInSeconds(10)
.withRepeatCount(10)
.build();
sched.rescheduleJob(oldTrigger.getKey(), newTrigger);

Update storage tables when webjob is shutting down

My question is similar to the below one.
Notification of when continuous Azure WebJob is stopping for NoAutomaticTrigger type jobs
I have used the idea from Amit's Blog but then hit a little roadblock
I have a file watcher set in the webjob which gets triggered if the webjob is shutdown from the portal.
I need to update a few flags in my storage tables before the webjob is terminated.
The problem is that my code seems to stop at a point where I am trying to retrive a record from storage table. I have exception handler around the below code and no exception message is written on the console.
Below is my code
CloudStorageAccount storageAccount = CloudStorageAccount.Parse("my storage key");
var tableClient = storageAccount.CreateCloudTableClient();
var table = tableClient.GetTableReference("myTable");
TableOperation operation = TableOperation.Retrieve("partKey", "rowKey");
var result = table.Execute(operation); // stucks here
if (result.Result != null)
{
MyEntity entity = (MyEntity)result.Result;
if (entity != null)
{
entity.IsRunning = false; //reset the flag
TableOperation update = TableOperation.InsertOrReplace(entity);
table.Execute(update); //update the record
}
}
I have increased the stopping_wait_time in settings.job to 300 seconds but still no luck.
You could use Microsoft.Azure.WebJobs.WebJobsShutdownWatcher
This is an implementation of Amit solution : WebJobs Graceful Shutdown
So I've found a solution doing this :
No modification in the Program.cs
class Program
{
static void Main()
{
var host = new JobHost();
host.Call(typeof(Startup).GetMethod("Start"));
host.RunAndBlock();
}
}
the graceful shutdown goes in your function :
public class Startup
{
[NoAutomaticTrigger]
public static void Start(TextWriter log)
{
var token = new Microsoft.Azure.WebJobs.WebJobsShutdownWatcher().Token;
//Shut down gracefully
while (!token.IsCancellationRequested)
{
// Do somethings
}
// This code will be executed once the webjob is going to shutdown
Console.Out.WriteLine("Webjob is shuting down")
}
}
After the while loop, you could also stop started tasks.

Resources