4

我正在运行在单独的 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值:

使用 CSRUN.EXE 更新设置

这是我在计算模拟器中看到的:

Azure Compute Emulator 中的跟踪输出

我还在 Windows Azure 上的实际部署中对此进行了测试,结果相同。

我真的没有看到任何原因(如果是设计使然的话),所以我认为这可能是一个错误。

我发现RoleEnvironment.InitializeCallbacks用于为Changed事件注册回调的内部方法每个进程只调用一次,而不是每个 AppDomain 调用一次。

只需执行以下操作即可通过公共RoleRuntimeBridge类调用此方法:Microsoft.WindowsAzure.ServiceRuntime.Implementation.Loader

new RoleRuntimeBridge().Initialize(null);

但是,只有最后一个执行此操作的 AppDomain 才会触发事件。因此,虽然这使我能够在“子”AppDomain 中触发事件,但它们不再在默认 AppDomain 中触发。

原因似乎是原生基础设施函数WaRegisterCallback只支持每个进程和回调类型一个回调。

任何帮助或指针都会被应用!

我已针对此问题在 Microsoft Connect 上提交了一个错误。

4

0 回答 0