Azure Webjobs - Define QueueName trigger on app.config - azure-webjobs

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

Related

Set a Pub Sub topic in Micronaut as per environment

I am following this guide to initialise a GCP Pub/Sub publisher.
The coding syntax is as follows:
#PubSubClient
public interface PubSubService {
#Topic("topic-a")
void send(final A a);
#Topic("topic-b")
void send(final B b);
}
I want to set this topic value based on the environment, as I will have a different topic for QA/DEV (say topic-a-qa and topic-b-qa).
Is there any way for me to set this String value in the #Topic annotation via or based on environment properties?
I do not have an option of have a different Project under the GCP account, also creating a different class for QA overriding this one is not so graceful when maintaining environments.
You can use placeholders inside Micronaut's annotations.
#PubSubClient
public interface PubSubService {
#Topic("${topic.a.name:topic-a}")
void send(final A a);
#Topic("${topic.b.name:topic-b}")
void send(final B b);
}
The expression ${topic.a.name:topic-a} instructs Micronaut to search for the value in the configuration under the topic.a.name key, and fall back to the value topic-a if the configuration key is not found. Then you can configure different topic names using e.g. application-qa.yml configuration file:
src/main/resources/application-qa.yml
topic:
a:
name: topic-a-qa
b:
name: topic-b-qa
Lastly, just make sure that when you run the application in the QA environment you set a proper active environment, e.g.
$ java -Dmicronaut.environments=qa -jar myapp.jar

Webjob always publishes as Continuous and not Triggered

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

WCF endpoints information in the config file for different environments

i wanted to know what is the best approach to save WCF endpoints information in the config file for different environments(DEV,TEST,PRE-PROD, PROD).
i am familiar with 1 way of doing this - 1. Maintain different config files(for each env) and deploy them accordingly.
Can someone please suggest the best way to do this ??
You can configure the endpoint at runtime with endpointbehaviors. In this behaviors you can get the machinename for example. Depending on the machinename you could set yout endpointaddress for your endpoint, and then start the service.
Here is a link : https://msdn.microsoft.com/en-us/library/vstudio/ms730137%28v=vs.100%29.aspx
EDIT:
So you write:
class CustomEndpointBehavior : IEndpointBehavior{
public void Validate(ServiceEndpoint endpoint)
{
// get here the address and rewrite it dependig on the machinemane e.g.
// remember to set the new address to the endpoint!
}
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
}
}
And in the class where you start the service, you need to set the CustomEndpointBehavior to the serviceHost, like:
serviceHost.Description.Behaviors.Add(new CustomEndpointBehavior());
I think this is the link. Create multiple configuration and then use pre build event to copy it. http://www.hanselman.com/blog/ManagingMultipleConfigurationFileEnvironmentsWithPreBuildEvents.aspx
In you have visual studio 2010 and above then it will be able to merge the config. https://msdn.microsoft.com/en-us/library/dd465326(v=vs.110).aspx

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