Webjob always publishes as Continuous and not Triggered - azure-webjobs

I have an Azure WebJob which I am publishing from visual studio 2017 to a Standard S1 App Service, the WebJob should be Triggered by CRON but always publishes as Continuous and I cannot figure out what I have done wrong (two other WebJobs publish fine)
I have the App Service set to 'Always On' in application settings
I have a settings.job file in the root with my schedule
{
"schedule": "0 3 5 * * 1-5"
}
My Program class
namespace EventPushUpdater
{
using Microsoft.Azure.WebJobs;
using MBL.AzureKeyVaultHelpers;
internal class Program
{
private static void Main()
{
Properties.Settings s = Properties.Settings.Default;
IKeyVault kv = new KeyVaultHelper(s.ClientId, s.ClientKey, s.KeyVaultRoot);
var config = new JobHostConfiguration();
config.DashboardConnectionString = kv.GetSecretValue(s.DashboardConnectionString);
config.StorageConnectionString = kv.GetSecretValue(s.DashboardConnectionString);
var host = new JobHost(config);
host.Call(typeof(Functions).GetMethod("PushEvents"), new { keyVault = kv });
}
}
}
And the function being called
public class Functions
{
[NoAutomaticTrigger]
public static void PushEvents(IKeyVault keyVault)
{
// do stuff
}
}

The first time you chose 'Publish as a WebJob', it asks you if you want Continuous or On Demand (which includes scheduled):
If you picked the wrong choice, simply delete webjob-publish-settings.json under Properties, and try again.
As an aside, your code is overly complex as you're needlessly using WebJobs SDK. Instead, your code can simply be:
static void Main()
{
// Do Stuff
}

You can switch between 'Continuous' and 'Triggered' modes by editing the webjob-publish-settings.json file that is found within the Properties folder of your WebJob project.
In this json file you can set "runMode:" to either Continuous or OnDemand (triggered) :
Continuous
OnDemand

Have you set { "is_singleton": true } in your settings.job?
If so you cannot run more than one instance of your WebJob. If you publish and run your WebJob to the Azure cloud you cannot never run it locally unless you use a different storage account.
Azure Webjob timer trigger does not fire

Related

Azure Queue Storage Triggered-Webjob - Dequeue Multiple Messages at a time

I have an Azure Queue Storage-Triggered Webjob. The process my webjob performs is to index the data into Azure Search. Best practice for Azure Search is to index multiple items together instead of one at a time, for performance reasons (indexing can take some time to complete).
For this reason, I would like for my webjob to dequeue multiple messages together so I can loop through, process them, and then index them all together into Azure Search.
However I can't figure out how to get my webjob to dequeue more than one at a time. How can this be accomplished?
For this reason, I would like for my webjob to dequeue multiple messages together so I can loop through, process them, and then index them all together into Azure Search.
According to your description, I suggest you could try to use Microsoft.Azure.WebJobs.Extensions.GroupQueueTrigger to achieve your requirement.
This extension will enable you to trigger functions and receive the group of messages instead of a single message like with [QueueTrigger].
More details, you could refer to below code sample and article.
Install:
Install-Package Microsoft.Azure.WebJobs.Extensions.GroupQueueTrigger
Program.cs:
static void Main()
{
var config = new JobHostConfiguration
{
StorageConnectionString = "...",
DashboardConnectionString = "...."
};
config.UseGroupQueueTriggers();
var host = new JobHost(config);
host.RunAndBlock();
}
Function.cs:
//Receive 10 messages at one time
public static void MyFunction([GroupQueueTrigger("queue3", 10)]List<string> messages)
{
foreach (var item in messages)
{
Console.WriteLine(item);
}
}
Result:
How would I get that changed to a GroupQueueTrigger? Is it an easy change?
In my opinion, it is an easy change.
You could follow below steps:
1.Install the package Microsoft.Azure.WebJobs.Extensions.GroupQueueTrigger from Nuget Package manager.
2.Change the program.cs file enable UseGroupQueueTriggers.
3.Change the webjobs functions according to your old triggered function.
Note:The group queue message trigger must use list.
As my code sample shows:
public static void MyFunction([GroupQueueTrigger("queue3", 10)]List<string> messages)
This function will get 10 messages from the "queue3" one time, so in this function you could change the function loop the list of the messages and process them, then index them all together into Azure Search.
4.Publish your webjobs to azure web apps.

Azure Webjobs - Define QueueName trigger on app.config

With the new release of Azure Webjobs 3.0.0 SDK it was announced the:
http://azure.microsoft.com/blog/2014/06/18/announcing-the-0-3-0-beta-preview-of-microsoft-azure-webjobs-sdk/
Improved function discovery
We added an ITypeLocator and INameResolver to enable customizing how the WebJobs SDK looks >for functions. This enables scenarios such as the following:
You can define functions where the QueueName is not explicit. You can read Queue names from a config source and specify this value at runtime.
Restrict function discovery to a particular class or assembly.
Dynamic functions at indexing time: you can define the function signature at runtime.
But there's no sample code on how to do it.
Does anyone know how to define the queue name at runtime (e.g. from app.config)?
If you take advantage of the new INameResolver in the configuration you can make your own implementation of the interface and replace it in the JobHostConfiguration. Take a look at this blog post where I made a small POC on the topic.
To use an external runtime service to define the name of the queue:
public class QueueNameResolver : INameResolver
{
public string Resolve(string practiceId)
{
//define in appsettings the queuename property
return CloudConfigurationManager.GetSetting("queuname");
//or some other service of your design
}
}
In the WebJob Code, Program.cs:
public void init()
{
// Retrieve storage account from connection string.
string azureJobStorageConnectionString = ConfigurationManager.ConnectionStrings["AzureWebJobsStorage"].ConnectionString;
var config =
new JobHostConfiguration(azureJobStorageConnectionString)
{
NameResolver = new QueueNameResolver()
};
host = new JobHost(config);
host.RunAndBlock();
}
as per azure doco

How to set Azure WebJob queue name at runtime?

I am developing an Azure WebJobs executable that I would like to use with multiple Azure websites. Each web site would need its own Azure Storage queue.
The problem I see is that the ProcessQueueMessage requires the queue name to be defined statically as an attribute of the first parameter inputText. I would rather have the queue name be a configuration property of the running Azure Website instance, and have the job executable read that at runtime when it starts up.
Is there any way to do this?
This can now be done. Simply create an INameResolver to allow you to resolve any string surrounded in % (percent) signs. For example, if this is your function with a queue name specified:
public static void WriteLog([QueueTrigger("%logqueue%")] string logMessage)
{
Console.WriteLine(logMessage);
}
Notice how there are % (percent) signs around the string logqueue. This means the job system will try to resolve the name using an INameResolver which you can create and then register with your job.
Here is an example of a resolver that will just take the string specified in the percent signs and look it up in your AppSettings in the config file:
public class QueueNameResolver : INameResolver
{
public string Resolve(string name)
{
return ConfigurationManager.AppSettings[name].ToString();
}
}
And then in your Program.cs file, you just need to wire this up:
var host = new JobHost(new JobHostConfiguration
{
NameResolver = new QueueNameResolver()
});
host.RunAndBlock();
This is probably an old question, but in case anyone else stumbles across this post. This is now supported by passing a JobHostConfiguration object into the JobHost constructor.
http://azure.microsoft.com/en-gb/documentation/articles/websites-dotnet-webjobs-sdk-storage-queues-how-to/#config
A slight better implementation of name resolver to avoid fetching from configuration all time. It uses a Dictionary to store the config values once retrieved.
using Microsoft.Azure.WebJobs;
using System.Collections.Generic;
using System.Configuration;
public class QueueNameResolver : INameResolver
{
private static Dictionary<string, string> keys = new Dictionary<string, string>();
public string Resolve(string name)
{
if (!keys.ContainsKey(name))
{
keys.Add(name, ConfigurationManager.AppSettings[name].ToString());
}
return keys[name];
}
}
Unfortunately, that is not possible. You can use the IBinder interface to bind dynamically to a queue but you will not have the triggering mechanism for it.
Basically, the input queue name has to be hardcoded if you want triggers. For output, you can use the previously mentioned interface.
Here is a sample for IBinder. The sample binds a blob dynamically but you can do something very similar for queues.

How to Ignore wsit-client.xml when calling web service if exists

The application I am working on calls many webservice. Just recently I have intergrated another web service that requires wsit-client.xml for Soap authentication.
That is working now but all the other SOAP services have stopped working.
Whenever any of them is being called, I see messages like
INFO: WSP5018: Loaded WSIT configuration from file: jar:file:/opt/atlasconf/atlas.20130307/bin/soap-sdd-1.0.0.jar!/META-INF/wsit-client.xml.
I suspect this is what is causing the Service calls to fail.
How can I cause the wsit-client.xml to be ignored for certain soap service calls?
Thanks
Fixed it by Using a Container and a Loader to configure a dynamic location for the wsit-client.xml. This way it is not automatically loaded. To do that, I first implemented a Container for the app as shown below
public class WsitClientConfigurationContainer extends Container {
private static final String CLIENT_CONFIG = "custom/location/wsit-client.xml";
private final ResourceLoader loader = new ResourceLoader() {
public URL getResource(String resource) {
return getClass().getClassLoader().getResource(CLIENT_CONFIG);
}
};
#Override
public <T> T getSPI(Class<T> spiType) {
if (spiType == ResourceLoader.class) {
return spiType.cast(loader);
}
return null;
}
}
Then to use it in the Code I do this
URL WSDL_LOCATION = this.getClass().getResource("/path/to/wsdl/mysvc.wsdl");
WSService.InitParams initParams = new WSService.InitParams();
initParams.setContainer(new WsitClientConfigurationContainer());
secGtwService = WSService.create(WSDL_LOCATION, SECGTWSERVICE_QNAME, initParams);
And it works like magic

Problem with Custom TFS Web Service Plugin

i'm not sure that what im going to do is the right so i first of all tell you my issue.
I have TFS as Bugtracking System and another system for tracking the worktime. I want that if a workitem status changes the other system changes the status too.
What i did until now is the following.
I wrote a plugin for the TFS web service were i catch the WorkItemChangedEvent.
public EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext, NotificationType notificationType, object notificationEventArgs,
out int statusCode, out string
statusMessage, out ExceptionPropertyCollection properties)
{
statusCode = 0;
properties = null;
statusMessage = String.Empty;
try
{
if (notificationType == NotificationType.Notification && notificationEventArgs is WorkItemChangedEvent)
{
WorkItemChangedEvent ev = notificationEventArgs as WorkItemChangedEvent;
EventLog.WriteEntry("WorkItemChangedEventHandler", "WorkItem " + ev.WorkItemTitle + " was modified");
}
}
catch (Exception)
{
}
return EventNotificationStatus.ActionPermitted;
}
I droped the DLL in C:\Program Files\Microsoft Team Foundation Server 2010\Application Tier\Web Services\bin\Plugins
but i looks like the extension is never called. So nothing apears in the event log.
But if i try to debug the service like in this post http://geekswithblogs.net/jakob/archive/2010/10/27/devleoping-and-debugging-server-side-event-handlers-in-tfs-2010.aspx
i cant hook on the process. So debugging does not work.
Why i cant debug the service? And is there a better way to do this?
Not sure if you fixed this but to me it looks like you are missing the Subscription method in the class.
public Type[] SubscribedTypes()
{
return new Type[1] {typeof(WorkItemChangedEvent)};
}
Without this your plugin will never get hit thus you will be unable to debug.
To debug the w3wp.exe process, you need to be running Visual Studio as an administrator.
From the menu, select Debug > Attach to process (or Ctrl-Alt-P)
Select Show processes from all users and Show processes in all sessions.
Find the w3wp.exe process that corresponds to your TFS Application Pool, and attach to it.
I notice that you're using EventLog.WriteEntry() - have you registered the event source previously in your code? To avoid the registration (which requires admin permissions), you might try using the TFS logger:
TeamFoundationApplication.Log("WorkItem " + ev.WorkItemTitle + " was modified", 0, System.Diagnostics.EventLogEntryType.Information);