Ejemplo n.º 1
0
        /// <summary>
        /// Gets the node.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="nodeName">Name of the node.</param>
        /// <returns></returns>
        private static WebFarmNode GetNode(RockContext rockContext, string nodeName)
        {
            var webFarmNodeService = new WebFarmNodeService(rockContext);
            var webFarmNode        = webFarmNodeService.Queryable().Single(wfn => wfn.NodeName == nodeName);

            return(webFarmNode);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Gets the node record, potentially creating it.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="nodeName">Name of the node.</param>
        /// <param name="pollingInterval">The polling interval.</param>
        /// <returns>
        ///   <c>true</c> if [is polling interval in use] [the specified node name]; otherwise, <c>false</c>.
        /// </returns>
        private static bool IsPollingIntervalInUse(RockContext rockContext, string nodeName, decimal pollingInterval)
        {
            Debug($"Checking poll interval {pollingInterval}");

            var webFarmNodeService = new WebFarmNodeService(rockContext);
            var anyMatches         = webFarmNodeService.Queryable().Any(wfn =>
                                                                        wfn.NodeName != nodeName &&
                                                                        wfn.CurrentLeadershipPollingIntervalSeconds == pollingInterval);

            return(anyMatches);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Handles the ItemDataBound event of the rNodes control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Web.UI.WebControls.RepeaterItemEventArgs"/> instance containing the event data.</param>
        protected void rNodes_ItemDataBound(object sender, System.Web.UI.WebControls.RepeaterItemEventArgs e)
        {
            var viewModel = e.Item.DataItem as WebFarmNodeService.NodeViewModel;

            if (viewModel == null)
            {
                return;
            }

            var spanLastSeen = e.Item.FindControl("spanLastSeen");
            var lChart       = e.Item.FindControl("lChart") as Literal;
            var lLastSeen    = e.Item.FindControl("lLastSeen") as Literal;

            spanLastSeen.Visible = viewModel.IsUnresponsive;
            lLastSeen.Text       = WebFarmNodeService.GetHumanReadablePastTimeDifference(viewModel.LastSeen);

            // Show chart for responsive nodes
            if (viewModel.IsActive && !viewModel.IsUnresponsive && viewModel.Metrics.Count() > 1)
            {
                var samples = WebFarmNodeMetricService.CalculateMetricSamples(viewModel.Metrics, _cpuMetricSampleCount, ChartMinDate, _chartMaxDate);
                var html    = GetChartHtml(samples);
                lChart.Text = html;
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Does the leadership poll.
        /// </summary>
        internal static async Task DoLeadershipPollAsync()
        {
            // If another node pinged this node, then that node is the leader, not this one
            if (_wasPinged)
            {
                Debug("My time to poll. I was pinged, so I'm not the leader");
                _wasPinged = false;
                return;
            }

            Debug("My time to poll. I was not pinged, so I'm starting leadership duties");

            // Ping other nodes with a unique key for this ping-pong round
            var pollingTime = RockDateTime.Now;

            _leadershipPingKey = Guid.NewGuid();
            PublishEvent(EventType.Ping, payload: _leadershipPingKey.Value.ToString());

            // Assert this node's leadership in the database
            using (var rockContext = new RockContext())
            {
                var webFarmNodeService = new WebFarmNodeService(rockContext);
                var nodes      = webFarmNodeService.Queryable().ToList();
                var thisNode   = nodes.FirstOrDefault(wfn => wfn.NodeName == NodeName);
                var otherNodes = nodes.Where(wfn => wfn.NodeName != NodeName);

                if (!thisNode.IsLeader)
                {
                    AddLog(rockContext, WebFarmNodeLog.SeverityLevel.Info, _nodeId, EventType.Availability, $"{NodeName} assumed leadership");
                }

                thisNode.IsLeader         = true;
                thisNode.IsActive         = true;
                thisNode.LastSeenDateTime = pollingTime;
                thisNode.StoppedDateTime  = null;

                foreach (var otherNode in otherNodes)
                {
                    otherNode.IsLeader = false;
                }

                rockContext.SaveChanges();
            }

            // Get polling wait time
            var pollingWaitTimeSeconds = GetMaxPollingWaitSeconds();

            // Wait a maximum of 10 seconds for responses
            await Task.Delay(TimeSpan.FromSeconds(pollingWaitTimeSeconds)).ContinueWith(t =>
            {
                // Clear the ping pong key because responses are now late and no longer accepted
                _leadershipPingKey = null;

                Debug("Checking for unresponsive nodes");

                using (var rockContext = new RockContext())
                {
                    var webFarmNodeService = new WebFarmNodeService(rockContext);
                    var unresponsiveNodes  = webFarmNodeService.Queryable()
                                             .Where(wfn =>
                                                    wfn.LastSeenDateTime < pollingTime &&
                                                    wfn.IsActive &&
                                                    wfn.NodeName != NodeName)
                                             .ToList();

                    Debug($"I found {unresponsiveNodes.Count} unresponsive nodes");

                    foreach (var node in unresponsiveNodes)
                    {
                        // Write to log if the server was thought to be active but did not respond
                        AddLog(rockContext, WebFarmNodeLog.SeverityLevel.Critical, node.Id, EventType.Availability, $"{node.NodeName} was marked active but did not respond to a ping");
                        node.IsActive = false;
                    }

                    rockContext.SaveChanges();
                }
            });
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Stage 1 Start.
        /// Called before Hot load caches and start-up activities( EF migrations etc )
        /// </summary>
        public static void StartStage1()
        {
            if (_startStage != 0)
            {
                LogException($"Web Farm cannot start stage 1 when at stage {_startStage}");
                return;
            }

            Debug("Start Stage 1");

            using (var rockContext = new RockContext())
            {
                // Check that the WebFarmEnable = true.If yes, continue
                if (!IsEnabled())
                {
                    return;
                }

                // Check license key in the SystemSetting
                if (!HasValidKey())
                {
                    return;
                }

                _isWebFarmEnabledAndUnlocked = true;

                // Initialize the performance counters that will be used when logging metrics
                InitializePerformanceCounters();

                // Load upper and lower polling interval settings
                var lowerLimitSeconds = GetLowerPollingLimitSeconds();
                var upperLimitSeconds = GetUpperPollingLimitSeconds();

                // Find node record in DB using node name, if not found create a new record
                var webFarmNodeService = new WebFarmNodeService(rockContext);
                var webFarmNode        = webFarmNodeService.Queryable().FirstOrDefault(wfn => wfn.NodeName == NodeName);
                var isNewNode          = webFarmNode == null;

                if (isNewNode)
                {
                    webFarmNode = new WebFarmNode
                    {
                        NodeName = NodeName
                    };

                    webFarmNodeService.Add(webFarmNode);
                    rockContext.SaveChanges();
                }

                _nodeId = webFarmNode.Id;

                // Determine leadership polling interval. If provided in database( ConfiguredLeadershipPollingIntervalSeconds ) use that
                // otherwise randomly select a number between upper and lower limits
                const int maxGenerationAttempts = 100;
                var       generationAttempts    = 1;

                _pollingIntervalSeconds =
                    webFarmNode.ConfiguredLeadershipPollingIntervalSeconds ??
                    GeneratePollingIntervalSeconds(lowerLimitSeconds, upperLimitSeconds);

                var isPollingIntervalInUse = IsPollingIntervalInUse(rockContext, NodeName, _pollingIntervalSeconds);

                while (generationAttempts < maxGenerationAttempts && isPollingIntervalInUse)
                {
                    generationAttempts++;
                    _pollingIntervalSeconds = GeneratePollingIntervalSeconds(lowerLimitSeconds, upperLimitSeconds);
                    isPollingIntervalInUse  = IsPollingIntervalInUse(rockContext, NodeName, _pollingIntervalSeconds);
                }

                if (isPollingIntervalInUse)
                {
                    var errorMessage = $"Web farm node {NodeName} did not successfully pick a polling interval after {maxGenerationAttempts} attempts";
                    AddLog(rockContext, WebFarmNodeLog.SeverityLevel.Warning, webFarmNode.Id, EventType.Error, errorMessage);

                    // Try to use the maximum value
                    _pollingIntervalSeconds = upperLimitSeconds;
                    isPollingIntervalInUse  = IsPollingIntervalInUse(rockContext, NodeName, _pollingIntervalSeconds);

                    if (isPollingIntervalInUse)
                    {
                        LogException($"{errorMessage} and could not use the maximum polling limit");
                        return;
                    }
                }

                // Save the polling interval
                // If web.config set to run jobs make IsCurrentJobRunner = true
                // Set StoppedDateTime to null
                // Update LastRestartDateTime to now
                webFarmNode.CurrentLeadershipPollingIntervalSeconds = _pollingIntervalSeconds;
                webFarmNode.IsCurrentJobRunner  = IsCurrentJobRunner();
                webFarmNode.StoppedDateTime     = null;
                webFarmNode.LastRestartDateTime = ProcessStartDateTime;
                webFarmNode.LastSeenDateTime    = ProcessStartDateTime;
                webFarmNode.IsActive            = false;

                // Write to ClusterNodeLog -Startup Message
                AddLog(rockContext, WebFarmNodeLog.SeverityLevel.Info, webFarmNode.Id, EventType.Startup, $"Process ID: {ProcessId}");

                rockContext.SaveChanges();
            }

            _startStage = 1;
            Debug("Done with Stage 1");
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Shows the mode where the user is only viewing an existing streak type
        /// </summary>
        private void ShowViewMode()
        {
            if (!IsViewMode())
            {
                return;
            }

            var canEdit = CanEdit();

            btnEdit.Visible = canEdit;

            pnlEditDetails.Visible = false;
            pnlViewDetails.Visible = true;
            HideSecondaryBlocks(false);

            // Load values from system settings
            var minPolling    = RockWebFarm.GetLowerPollingLimitSeconds();
            var maxPolling    = RockWebFarm.GetUpperPollingLimitSeconds();
            var minDifference = RockWebFarm.GetMinimumPollingDifferenceSeconds();
            var pollingWait   = RockWebFarm.GetMaxPollingWaitSeconds();

            var maskedKey = SystemSettings.GetValue(SystemSetting.WEBFARM_KEY).Masked();

            if (maskedKey.IsNullOrWhiteSpace())
            {
                maskedKey = "None";
            }

            // Build the description list with the values
            var descriptionList = new DescriptionList();

            descriptionList.Add("Key", string.Format("{0}", maskedKey));
            descriptionList.Add("Min Polling Limit", string.Format("{0} seconds", minPolling));
            descriptionList.Add("Max Polling Limit", string.Format("{0} seconds", maxPolling));
            descriptionList.Add("Min Polling Difference", string.Format("{0} seconds", minDifference));
            descriptionList.Add("Max Polling Wait", string.Format("{0} seconds", pollingWait));

            var unresponsiveMinutes  = 10;
            var unresponsiveDateTime = RockDateTime.Now.AddMinutes(0 - unresponsiveMinutes);

            // Bind the grid data view models
            using (var rockContext = new RockContext())
            {
                var webFarmNodeService       = new WebFarmNodeService(rockContext);
                var webFarmNodeMetricService = new WebFarmNodeMetricService(rockContext);

                var viewModels = webFarmNodeService.Queryable()
                                 .AsNoTracking()
                                 .Select(wfn => new WebFarmNodeService.NodeViewModel
                {
                    PollingIntervalSeconds = wfn.CurrentLeadershipPollingIntervalSeconds,
                    IsJobRunner            = wfn.IsCurrentJobRunner,
                    IsActive       = wfn.IsActive,
                    IsUnresponsive = wfn.IsActive && !wfn.StoppedDateTime.HasValue && wfn.LastSeenDateTime < unresponsiveDateTime,
                    IsLeader       = wfn.IsLeader,
                    NodeName       = wfn.NodeName,
                    LastSeen       = wfn.LastSeenDateTime,
                    Id             = wfn.Id,
                    Metrics        = wfn.WebFarmNodeMetrics
                                     .Where(wfnm =>
                                            wfnm.MetricType == WebFarmNodeMetric.TypeOfMetric.CpuUsagePercent &&
                                            wfnm.MetricValueDateTime >= ChartMinDate &&
                                            wfnm.MetricValueDateTime <= _chartMaxDate)
                                     .Select(wfnm => new WebFarmNodeMetricService.MetricViewModel
                    {
                        MetricValueDateTime = wfnm.MetricValueDateTime,
                        MetricValue         = wfnm.MetricValue
                    })
                                     .ToList()
                })
                                 .ToList();

                rNodes.DataSource = viewModels.OrderBy(n => n.NodeName);
                rNodes.DataBind();
            }

            lDescription.Text = descriptionList.Html;
        }