From 724627ea27c4c5010545199839ca84da80d0b87d Mon Sep 17 00:00:00 2001 From: Paul Marvin Date: Wed, 12 Jul 2017 11:11:36 -0500 Subject: [PATCH] SF-6804: StackifyLib: Frequent Calls to GetEC2InstanceId * Retrieve ec2 instance-id from local metadata endpoint no more than once per hour * Add config in case the threshold requires adjustment "in the wild" --- Src/StackifyLib/Config.cs | 13 ++++- Src/StackifyLib/Models/EnvironmentDetail.cs | 63 ++++++++++++++++++--- 2 files changed, 67 insertions(+), 9 deletions(-) diff --git a/Src/StackifyLib/Config.cs b/Src/StackifyLib/Config.cs index 18249f8..8085894 100644 --- a/Src/StackifyLib/Config.cs +++ b/Src/StackifyLib/Config.cs @@ -74,7 +74,16 @@ public static void LoadSettings() { ErrorSessionGoodKeys = CaptureErrorSessionWhitelist.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries).ToList(); } - + + // SF-6804: Frequent Calls to GetEC2InstanceId + var captureEc2InstanceMetadataUpdateThresholdMinutes = Get("Stackify.Ec2InstanceMetadataUpdateThresholdMinutes", ""); + if (string.IsNullOrWhiteSpace(captureEc2InstanceMetadataUpdateThresholdMinutes) == false) + { + if (int.TryParse(captureEc2InstanceMetadataUpdateThresholdMinutes, out int minutes) && minutes > 0) + { + Ec2InstanceMetadataUpdateThresholdMinutes = minutes; + } + } } catch (Exception ex) { @@ -109,6 +118,8 @@ public static void LoadSettings() public static string CaptureErrorCookiesBlacklist { get; set; } = ".ASPXAUTH"; + public static int Ec2InstanceMetadataUpdateThresholdMinutes { get; set; } = 60; + /// /// Attempts to fetch a setting value given the key. diff --git a/Src/StackifyLib/Models/EnvironmentDetail.cs b/Src/StackifyLib/Models/EnvironmentDetail.cs index 2919b2e..68fb481 100644 --- a/Src/StackifyLib/Models/EnvironmentDetail.cs +++ b/Src/StackifyLib/Models/EnvironmentDetail.cs @@ -100,7 +100,10 @@ private void GetAzureInfo() } // http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html#d0e30002 - const string EC2InstanceIdUrl = "http://169.254.169.254/latest/meta-data/instance-id"; + private const string EC2InstanceIdUrl = "http://169.254.169.254/latest/meta-data/instance-id"; + public static readonly object ec2InstanceLock = new object(); + private static DateTimeOffset? ec2InstanceIdLastUpdate = null; + private static string ec2InstanceId = null; /// /// Get the EC2 Instance name if it exists else null @@ -108,6 +111,22 @@ private void GetAzureInfo() #if NET451 || NET45 || NET40 public static string GetEC2InstanceId() { + string r = null; + + // SF-6804: Frequent Calls to GetEC2InstanceId + bool skipEc2InstanceIdUpdate = false; + var threshold = TimeSpan.FromMinutes(Config.Ec2InstanceMetadataUpdateThresholdMinutes); + lock (ec2InstanceLock) + { + skipEc2InstanceIdUpdate = ec2InstanceIdLastUpdate != null && ec2InstanceIdLastUpdate < DateTimeOffset.UtcNow.Subtract(threshold); + r = string.IsNullOrWhiteSpace(ec2InstanceId) ? null : ec2InstanceId; + } + + if (skipEc2InstanceIdUpdate) + { + return r; + } + try { var request = (HttpWebRequest)WebRequest.Create(EC2InstanceIdUrl); @@ -123,22 +142,44 @@ public static string GetEC2InstanceId() using (var reader = new StreamReader(responseStream, encoding)) { var id = reader.ReadToEnd(); - return string.IsNullOrWhiteSpace(id) ? null : id; + r = string.IsNullOrWhiteSpace(id) ? null : id; } } } - return null; } } catch // if not in aws this will timeout { - return null; + r = null; } + lock (ec2InstanceLock) + { + ec2InstanceId = r; + ec2InstanceIdLastUpdate = DateTimeOffset.UtcNow; + } + + return r; } #else public static async Task GetEC2InstanceId() { + string r = null; + + // SF-6804: Frequent Calls to GetEC2InstanceId + bool skipEc2InstanceIdUpdate = false; + var threshold = TimeSpan.FromMinutes(Config.Ec2InstanceMetadataUpdateThresholdMinutes); + lock (ec2InstanceLock) + { + skipEc2InstanceIdUpdate = ec2InstanceIdLastUpdate != null && ec2InstanceIdLastUpdate < DateTimeOffset.UtcNow.Subtract(threshold); + r = string.IsNullOrWhiteSpace(ec2InstanceId) ? null : ec2InstanceId; + } + + if (skipEc2InstanceIdUpdate) + { + return r; + } + try { @@ -152,17 +193,23 @@ public static async Task GetEC2InstanceId() if (statusCode >= 200 && statusCode < 300) { string id = await content.Content.ReadAsStringAsync(); - return string.IsNullOrWhiteSpace(id) ? null : id; + r = string.IsNullOrWhiteSpace(id) ? null : id; } } } catch // if not in aws this will timeout { - return null; + r = null; } - return null; + lock (ec2InstanceLock) + { + ec2InstanceId = r; + ec2InstanceIdLastUpdate = DateTimeOffset.UtcNow; + } + + return r; } #endif /// @@ -269,7 +316,7 @@ public EnvironmentDetail(bool loadDetails) this.IsAzureWorkerRole = false; //Logger global properties would override everything - + if (!string.IsNullOrEmpty(Config.AppName)) { ConfiguredAppName = Config.AppName;