Is it possible delay making a virtual machine role available untill startup tasks complete?
I have a few tasks I need to complete on virtual machine start before the machine can safely be added to the load balancer. Is there a way to do this?
Found the solution. In the VM Role Startup windows service I can handle the RoleEnvironment.StatusCheck event. I can then call SetBusy() to tell prevent the instance being available in the load balancer.
private void RoleEnvironmentStatusCheck(object sender, RoleInstanceStatusCheckEventArgs e)
{
if (this.busy)
{
e.SetBusy();
}
statusCheckWaitHandle.Set();
}
I believe that setting the taskType attribute to simple will make the Role wait for the task completion before actually starting:
<ServiceDefinition name="MyService" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
<WebRole name="WebRole1">
<Startup>
<Task commandLine="Startup.cmd" executionContext="limited" taskType="simple">
</Task>
</Startup>
</WebRole>
</ServiceDefinition>
Related
I have a problem with a WCF service which is hosted on a Windows 2016 VM in Azure running in IIS 10.
The service is basically a test service where I put in the operationContract a Thread.Sleep (timer) and the duration is sent as a parameter defined in the operationContract.
The problem is that specifying a sleep duration of up to 4.2 seconds runs without problems, but if I call the service specifying 5 seconds to run. The task process ends at 5 seconds, with the code above, the internal logger notifies me that I am done but for some reason WCFTestClient is still waiting for a response and continues to wait until the configured timeout is reached. In this case I have my Receive_timeout and Send 10 minutes on both sides in the service config and in the client config.
As proof I created a local environment in my network, mounting the service on a server, and here after 5 minutes or even a 9 minute test test client behaves as expected.
[OperationContract]
public void TestServiceTimeout (int timer)
{
try
{
log.Info("Start test Service");
System.Threading.Thread.Sleep(timer);
log.Info("End test srervices");
}
catch (Exception ex)
{
log.Error($"An error ocurred. Details: {ex.Message}");
throw;
}
}
Web.Config IIS
<binding name="Control.ws.sTest.customBinding0" receiveTimeout="00:20:00"
sendTimeout="00:20:00">
<binaryMessageEncoding />
<httpTransport />
</binding>
WCFTestClient Config
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_sFacturacion" sendTimeout="00:10:00" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:60000/ws/sFacturacion.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_sFacturacion"
contract="sFacturacion" name="BasicHttpBinding_sFacturacion" />
</client>
WCF will not shut down the client actively, even if the server is offline, the client will catch the communication exception after the configured timeout is reached.
Please refer to the below definition of the Timeout settings.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/configuring-timeout-values-on-a-binding
Feel free to let me know if there is anything I can help with.
I'm relatively new to Azure development and need some help overcoming the following predicament:
I have an executable that I need to run as part of my Azure service startup. The executable needs access to one of the service's application settings.
So I added the following to my csdef (the batch script just runs the executable with output redirected to a file):
<Startup>
<Task commandLine="StartupTask.cmd" executionContext="elevated" taskType="background">
<Environment>
<Variable name="Var">
<RoleInstanceValue
xpath="/RoleEnvironment/CurrentInstance/ConfigurationSettings/ConfigurationSetting[#name='SomeAppSetting']/#value" />
</Variable>
</Environment>
</Task>
</Startup>
Adding the task caused the deployment to fail and after much hair tearing I realized it was because SomeAppSetting value was too long (see http://blogs.msdn.com/b/cie/archive/2013/07/30/windows-azure-role-recycling-due-to-setting-more-than-256-character-in-environmental-variable-through-azure-start-up-task.aspx) and now I'm at a loss of what to do.
Are the following possible:
1. Accessing the role environment from inside the executable somehow?
2. Passing the setting value to the script as a parameter?
Thanks in advance for any tips!
One option would be to move the app setting from the service configuration to blob storage from where it is accessible to both the startup task and the running service.
You can load the RoleEnvironment information in a PowerShell script (which you load in the startup task) which will let you access your ServiceConfiguration settings:
[Reflection.Assembly]::LoadWithPartialName("Microsoft.WindowsAzure.ServiceRuntime")
$mySetting = [Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment]::GetConfigurationSettingValue("MySetting")
if($mySetting -eq "True"){ .....}
In my ServiceConfiguration (.cscfg) I have a setting called MySettig which is True/False.
I need a help with creating virtual directory pointing to local storage in Windows Azure (production environment). I can set up a virtual directory manually but it is being erased every time Azure is restarted. The clue is to create the virtual directory via config file when I upload a package of my project on Azure. The question is how to create such directory so that it is pointing to local storage.
Thx in advance for any suggestions.
Best Regards,
Darek
I suggest you create the virtual directory by interacting with IIS in the WebRole's OnStart method:
public class WebRole : RoleEntryPoint
{
public override bool OnStart()
{
// Connect to the IIS site.
using (var manager = new Microsoft.Web.Administration.ServerManager())
{
var localResourcePath = RoleEnvironment.GetLocalResource("MyResource").RootPath;
// Add to the root application.
var rootSite = manager.Sites[RoleEnvironment.CurrentRoleInstance.Id + "_Web"];
var rootApplication = rootSite.Applications["/"];
rootApplication.VirtualDirectories.Add("/myVdir", localResourcePath);
// Save
manager.CommitChanges();
}
...
}
}
If I'm right you'll need to set the execution context to elevated for this to work. You can do this in the ServiceDefintion.csdef:
<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="MyProject" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2012-05.1.7">
<WebRole name="MyRole" vmsize="Small" enableNativeCodeExecution="true">
<Runtime executionContext="elevated" />
...
</WebRole>
</ServiceDefinition>
Note: You'll need to reference Microsoft.Web.Administration.dll (C:\Windows\System32\inetsrv)
I have moderate experience in developing web applications using spring.net 4.0 , nhibernate 3.0 for ASP.net based web applications. Recently I ran into a situation where I needed to use spring.net to inject my service dependencies which belong to the WorkerRole class. I created the app.config file as I normally did with the web.config files on for spring. Here it is for clarity. (I have excluded the root nodes)
<configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.WebContextHandler, Spring.Web" requirePermission="false" />
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" requirePermission="false" />
<section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core" />
</sectionGroup>
</configSections>
<spring>
<context>
<!-- Application services and data access that has been previously developed and tested-->
<resource uri="assembly://DataAccess/data-access-config.xml" />
<resource uri="assembly://Services/service-config.xml" />
<resource uri="AOP.xml" />
<resource uri="DI.xml"/>
</context>
<parsers>
<parser type="Spring.Data.Config.DatabaseNamespaceParser, Spring.Data" />
<parser type="Spring.Transaction.Config.TxNamespaceParser, Spring.Data" />
<parser type="Spring.Aop.Config.AopNamespaceParser, Spring.Aop" />
</parsers>
</spring>
Similarly Here's the AOP.xml
<object id="FilterServiceProxy" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
<property name="proxyInterfaces" value="Domain.IFilterService"/>
<property name="target" ref="FilterService"/>
<property name="interceptorNames">
<list>
<value>UnhandledExceptionThrowsAdvice</value>
<value>PerformanceLoggingAroundAdvice</value>
</list>
</property>
</object>
</objects>
and the DI.xml
<object type="FilterMt.WorkerRole, FilterMt" >
<property name="FilterMtService1" ref="FilterServiceProxy"/>
</object>
However, I was unable to inject any dependencies into the worker role. Can someone please let me know what I am doing wrong here ? Is there a different way to configure Spring.net DI for windows azure applications ?
I don't get any configuration errors but I see that the dependencies have not been injected because the property object to which I've tried injection, remains null.
Based on my experience, you cannot inject anything into your WorkerRole class (the class that implements RoleEntryPoint). What I do, so far with Unity (I also built my own helper for Unity to help me inject Azure settings), is that I have my own infrastructure that runs and is built by Unity, but I create it in the code for the worker role.
For example, I initialize the dependency container in my OnStart() method of RoleEntry point, where I resolve anything I need. Then in my Run() method I call a method on my resolved dependency.
Here is a quick, stripped off version of my RoleEntryPoint's implementation:
public class WorkerRole : RoleEntryPoint
{
private UnityServiceHost _serviceHost;
private UnityContainer _container;
public override void Run()
{
// This is a sample worker implementation. Replace with your logic.
Trace.WriteLine("FIB.Worker entry point called", "Information");
using (this._container = new UnityContainer())
{
this._container.LoadConfiguration();
IWorker someWorker = this._container.Resolve<IWorker>();
someWorker.Start();
IWorker otherWorker = this._container.Resolve<IWorker>("otherWorker");
otherWorker.Start();
while (true)
{
// sleep 30 minutes. we don't really need to do anything here.
Thread.Sleep(1800000);
Trace.WriteLine("Working", "Information");
}
}
}
public override bool OnStart()
{
// Set the maximum number of concurrent connections
ServicePointManager.DefaultConnectionLimit = 12;
// For information on handling configuration changes
// see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.
this.CreateServiceHost();
return base.OnStart();
}
public override void OnStop()
{
this._serviceHost.Close(TimeSpan.FromSeconds(30));
base.OnStop();
}
private void CreateServiceHost()
{
this._serviceHost = new UnityServiceHost(typeof(MyService));
var binding = new NetTcpBinding(SecurityMode.None);
RoleInstanceEndpoint externalEndPoint =
RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["ServiceEndpoint"];
string endpoint = String.Format(
"net.tcp://{0}/MyService", externalEndPoint.IPEndpoint);
this._serviceHost.AddServiceEndpoint(typeof(IMyService), binding, endpoint);
this._serviceHost.Open();
}
As you can see, my own logic is IWorker interface and I can have as many implementations as I want, and I instiate them in my Run() method. What I do more is to have a WCF Service, again entirely configured via DI with Unity. Here is my IWorker interface:
public interface IWorker : IDisposable
{
void Start();
void Stop();
void DoWork();
}
And that's it. I don't have any "hard" dependencies in my WorkerRole, just the Unity Container. And I have very complex DIs in my two workers, everything works pretty well.
The reason why you can't interfere directly with your WorkerRole.cs class, is that it is being instantiated by the Windows Azure infrastructure, and not by your own infrastructure. You have to accept that, and built your infrastructure within the WorkerRole appropriate methods. And do not forget that you must never quit/break/return/exit the Run() method. Doing so will flag Windows Azure infrastructure that there is something wrong with your code and will trigger role recycling.
Hope this helps.
I know this is an old question, but I'm going through the same learning curve and would like to share my findings for someone who struggles to understand the mechanics.
The reason you can't access DI in your worker role class is because this is run in a separate process in the OS, outside of IIS. Think of your WebRole class as being run in a Windows Service.
I've made a little experiment with my MVC web-site and WebRole class:
public class WebRole : RoleEntryPoint
{
public override void Run()
{
while (true)
{
Thread.Sleep(10000);
WriteToLogFile("Web Role Run: run, Forest, RUN!");
}
}
private static void WriteToLogFile(string text)
{
var file = new System.IO.StreamWriter("D:\\tmp\\webRole.txt", true); // might want to change the filename
var message = string.Format("{0} | {1}", DateTime.UtcNow, text);
file.WriteLine(message);
file.Close();
}
}
This would write to a file a new string every 10 seconds (or so). Now start your Azure site in debugging mode, make sure the site deployed to Azure emulator and the debugger in VS has started. Check that the site is running and check that WebRole is writing to the file in question.
Now stop the IIS Express (or IIS if you are running it in full blown installation) without stopping the VS debugger. All operations in your web-site are stopped now. But if you check your temp file, the process is still running and you still get new lines added every 10 seconds. Until you stop the debugger.
So whatever you have loaded in memory of web-application is inside of the IIS and not available inside of Worker Role. And you need to re-configure your DI and other services from the scratch.
Hope this helps someone to better understand the basics.
I have an on premise service bus that is configured to handle messages from an azure queue. The problem i am having is that the host is reporting an msmq error saying that it could not create the error queue. Aside from the fact that it should not be using msmq, it also handles the messages with no problems despite the error so it does not seem to be critical.
My Host is running as a class library configured to start with the nservicebus.host.exe process.
Here is my host code and config:
internal class EndpointConfig : IConfigureThisEndpoint, AsA_Server, IWantCustomInitialization
{
#region IWantCustomInitialization Members
public void Init()
{
Configure.With()
.DefaultBuilder()
.AzureMessageQueue()
.JsonSerializer()
.UnicastBus()
.IsTransactional(true)
.InMemorySubscriptionStorage();
}
#endregion
}
Config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="UnicastBusConfig" type="NServiceBus.Config.UnicastBusConfig, NServiceBus.Core" />
<section name="AzureQueueConfig" type="NServiceBus.Config.AzureQueueConfig, NServiceBus.Azure"/>
<section name="MessageForwardingInCaseOfFaultConfig" type="NServiceBus.Config.MessageForwardingInCaseOfFaultConfig, NServiceBus.Core" />
</configSections>
<MessageForwardingInCaseOfFaultConfig ErrorQueue="error" />
<AzureQueueConfig QueueName="sender" ConnectionString="UseDevelopmentStorage=true" PeekInterval="5000" MaximumWaitTimeWhenIdle="60000" />
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedruntime version="v4.0" />
<requiredruntime version="v4.0.20506" />
</startup>
</configuration>
And Here is the actual Error Message:
2012-04-24 07:57:10,973 [1] ERROR NServiceBus.Utils.MsmqUtilities [(null)] <(nul
l)> - Could not create queue error#UseDevelopmentStorage=true or check its exist
ence. Processing will still continue.
System.Messaging.MessageQueueException (0x80004005): Message Queue service is no
t available.
at System.Messaging.MessageQueue.Create(String path, Boolean transactional)
at NServiceBus.Utils.MsmqUtilities.CreateQueue(String queueName, String accou
nt)
at NServiceBus.Utils.MsmqUtilities.CreateQueueIfNecessary(Address address, St
ring account)
EDIT: Adding .MessageForwardingInCaseOfFault() to the initialization corrected the issue.
Looks like AsA_Server assumes msmq, guess you'll have to configure the process manually
Adding .MessageForwardingInCaseOfFault() to the init method resolved the issue. Still feels like there is an underlying bug, but it is working.
I suspect that below described the next hurdle (not handling errors correctly) but i will have to try to force a failed message to verify.
As described in:
NServiceBus error queues in Azure