如何配置两类Azure Functions分别在指定环境运行?
环境限制实现方案
前置准备
确保所有环境配置统一的环境标识变量,推荐使用标准的ASPNETCORE_ENVIRONMENT,对应值:
- 开发环境(DEV):
Development - 集成环境(INT):
Integration - 预生产环境(STG):
Staging - 生产环境(PROD):
Production
一、RetryEventFunction 仅在STG/PROD环境运行
方案1:代码层面直接校验(兜底逻辑)
在函数入口添加环境判断,非目标环境直接跳过执行:
[FunctionName("RetryEventFunction")] public void RunQueue([QueueTrigger("%QueueName%", Connection = "StorageAccount")] string input) { var currentEnv = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Development"; var allowedEnvs = new[] { "Staging", "Production" }; if (!allowedEnvs.Contains(currentEnv)) { Log.Info($"CI Receiver: RetryEventFunction 禁止在 {currentEnv} 环境执行,已跳过"); return; } // 原有业务逻辑保持不变 try { Log.Info($"CI Receiver: Retry Event Function triggered. Input : {input}"); var queueMessage = JsonConvert.DeserializeObject<QueueModel>(input); EventData data = new EventData(queueMessage.Message); foreach (var prop in queueMessage.Headers) { data.Properties.Add(prop.Key, prop.Value); } if (IsRetryApplicable(data)) { ManageGeoSpetialData(data); Log.Info("CI Receiver: Retry Event Function processed successfully"); } else { Log.Info("CI Receiver: Retry Event Function skipped after exhausting specified maximum retries"); } } catch (Exception ex) { Log.Error($"CI Receiver: RetryEventFunction Event Consumer fails with Exception {ex.Message}, {ex.InnerException} and Stacktrace : {ex.StackTrace}"); } }
方案2:平台配置禁用函数(更符合Azure特性)
在各环境的配置中添加函数禁用开关:
- DEV/INT环境:配置
RetryEventFunction_Disabled=true - STG/PROD环境:配置
RetryEventFunction_Disabled=false(或不配置,默认启用)
此方案由Azure Functions平台直接拦截函数触发,无需执行到代码逻辑。
二、ProcessEvent 仅在DEV/INT环境运行
由于ProcessEvent是普通业务方法,直接在方法开头添加环境校验:
public void ProcessEvent(object data) { var currentEnv = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Development"; var allowedEnvs = new[] { "Development", "Integration" }; if (!allowedEnvs.Contains(currentEnv)) { Log.Info($"CI Receiver: ProcessEvent 禁止在 {currentEnv} 环境执行,已跳过"); return; } // 原有业务逻辑保持不变,注意补充原代码缺失的switch闭合括号和default分支 try { Constants.InitializeConstants(_configuration); var eventData = data as EventData; object eventType = ""; object eventAction = ""; object eventApplicationId = 0; eventData.Properties.TryGetValue(EventProperties.EventTypeProperty, out eventType); eventData.Properties.TryGetValue(EventProperties.ActionProperty, out eventAction); eventData.Properties.TryGetValue(EventProperties.ApplicationIdProperty, out eventApplicationId); Model.Properties properties; switch (Convert.ToString(eventType)) { case EventTypes.LoaderEventType: AssetEvent assetEvent = eventData.DeserializetoModel<AssetEvent>(Log); properties = assetEvent.Device.FirstOrDefault()?.Properties != null ? JsonConvert.DeserializeObject<Model.Properties>(assetEvent.Device.FirstOrDefault()?.Properties) : null; Asset loaderAsset = new Asset() { AssetPrimaryId = assetEvent.AssetPrimaryId, AssetID = assetEvent.AssetId, Make = assetEvent.Device.FirstOrDefault()?.Make, SerialNumber = assetEvent.Device.FirstOrDefault()?.SerialNumber, Type = assetEvent.AssetType, UCID = assetEvent.Device.FirstOrDefault()?.Ucid, ApplicationId = Convert.ToInt32(eventApplicationId), EquipmentId = assetEvent.Device.FirstOrDefault()?.EquipmentId, AssetKey = assetEvent.Device.FirstOrDefault()?.AssetKey, Model = properties?.Model }; SaveAssetInfo(loaderAsset, Convert.ToString(eventAction)); break; case EventTypes.PaverEventType: PaverEvent paverEvent = eventData.DeserializetoModel<PaverEvent>(Log); properties = paverEvent.Device.FirstOrDefault()?.Properties != null ? JsonConvert.DeserializeObject<Model.Properties>(paverEvent.Device.FirstOrDefault()?.Properties) : null; Asset paverAsset = new Asset() { AssetPrimaryId = paverEvent.Id, AssetID = paverEvent.AssetId, Make = paverEvent.Device.FirstOrDefault()?.Make, SerialNumber = paverEvent.Device.FirstOrDefault()?.SerialNumber, Type = paverEvent.AssetType, UCID = paverEvent.Device.FirstOrDefault()?.Ucid, ApplicationId = Convert.ToInt32(eventApplicationId), EquipmentId = paverEvent.Device.FirstOrDefault()?.EquipmentId, AssetKey = paverEvent.Device.FirstOrDefault()?.AssetKey, Model = properties?.Model }; SaveAssetInfo(paverAsset, Convert.ToString(eventAction)); break; default: Log.Info($"CI Receiver: 未匹配到EventType {eventType}"); break; } } catch (Exception ex) { _qaPublisher.PublishAsync(data, new PublisherProperties { Name = _configuration["QueueName"], StorageConnectionstring = _configuration["StorageAccount"] }); Log.Error($"CI Receiver - Exception occured during processing event. Exception Details : {ex.Message} and StackTrace : {ex.StackTrace}"); Log.Info($"For more details check if data is present in Queue: {_configuration["QueueName"]} otherwise ignore this exception"); } }
关键注意事项
- 环境变量统一:确保所有环境使用相同的环境变量标识,避免混用不同变量名导致判断失效。
- 配置优先级:Azure平台配置的函数禁用开关优先级高于代码逻辑,若平台已禁用函数,代码不会被执行。
- 代码完整性:原
ProcessEvent方法的switch语句缺少闭合括号和default分支,需补充完整以通过编译。
内容的提问来源于stack exchange,提问作者akil
相关产品推荐
相关产品推荐

