我正在运行在单独的 AppDomain 中托管代码的 Azure 服务。我需要处理这些 AppDomain 中的服务配置更改。为此,我正在监听RoleEnvironment.Changed事件。
但是,此事件仅在默认 AppDomain 中触发,而不在任何其他 AppDomain 中触发。但是,我可以通过在所有 AppDomain 中调用RoleEnvironment.GetConfigurationSettingValue来获取最新值。
我错过了什么,还是这是设计上的限制?
我需要让它工作,所以我认为我需要开发一个解决方法,其中只有默认的 AppDomain 监听Changed事件,然后使用一些基本的 IPC 将任何更改传达给其他 AppDomain。有没有人有更好的解决方法?
我创建了一个示例服务来说明我的问题:
public class WorkerRole : RoleEntryPoint
{
public override void Run()
{
AppDomain.CreateDomain("MySubdomain", null,
AppDomain.CurrentDomain.SetupInformation).DoCallBack(() =>
{
WorkerRole.EnableDevFabricTraceListener();
new Thread(WorkerRole.WorkerThreadProc).Start("CHILD");
});
WorkerRole.WorkerThreadProc("MAIN");
}
private static void WorkerThreadProc(object id)
{
Trace.TraceInformation(string.Format(
"[{0}] Starting", id), "Information");
RoleEnvironment.Changed += (sender, args) =>
{
Trace.TraceInformation(string.Format(
"[{0}] Role environment changed!", id), "Information");
};
string prevValue = null;
while (true)
{
string currValue = RoleEnvironment.GetConfigurationSettingValue(
"MySetting");
if (prevValue != currValue)
{
Trace.TraceInformation(string.Format(
"[{0}] MySetting={1}", id, currValue), "Information");
prevValue = currValue;
}
Thread.Sleep(1000);
}
}
// This is just a hack to enable tracing to the Azure Compute Emulator in
// other app domains.
private static void EnableDevFabricTraceListener()
{
try
{
const string className = "Microsoft.ServiceHosting.Tools.DevelopmentFabric.Runtime.DevelopmentFabricTraceListener";
const string assemblyName = "Microsoft.ServiceHosting.Tools.DevelopmentFabric.Runtime, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
var assembly = Assembly.Load(assemblyName);
var computeEmulatorTraceListenerType = assembly.GetType(className);
var computeEmulatorTraceListener = (TraceListener)Activator.CreateInstance(computeEmulatorTraceListenerType);
Trace.Listeners.Add(computeEmulatorTraceListener);
}
catch
{
// suppressed
}
}
}
我在 Azure Compute Emulator 中运行此服务并用于csrun.exe
更新MySetting
值:
这是我在计算模拟器中看到的:
我还在 Windows Azure 上的实际部署中对此进行了测试,结果相同。
我真的没有看到任何原因(如果是设计使然的话),所以我认为这可能是一个错误。
我发现RoleEnvironment.InitializeCallbacks
用于为Changed
事件注册回调的内部方法每个进程只调用一次,而不是每个 AppDomain 调用一次。
只需执行以下操作即可通过公共RoleRuntimeBridge
类调用此方法:Microsoft.WindowsAzure.ServiceRuntime.Implementation.Loader
new RoleRuntimeBridge().Initialize(null);
但是,只有最后一个执行此操作的 AppDomain 才会触发事件。因此,虽然这使我能够在“子”AppDomain 中触发事件,但它们不再在默认 AppDomain 中触发。
原因似乎是原生基础设施函数WaRegisterCallback
只支持每个进程和回调类型一个回调。
任何帮助或指针都会被应用!