public async Task <bool> ReadIfPoisonWaitsForHourAsync(Hour hour)
        {
            ThrowOn.IsNull(hour, "hour cannot be null to check poison waits");

            var timeThreshold = hour.GetHourEnd();

            return(await this.processControlRepository.HasRunSuccessfully(ProcessControlId.CollectWaitStatistics, timeThreshold));
        }
        public async Task <bool> ReadPoisonWaitsForHourAsync(Hour hour, int serverId)
        {
            ThrowOn.IsNull(hour, "hour cannot be null to check poison waits");
            ThrowOn.IsLessThanOne(serverId, "server must be valid server id to check poison waits");

            using (var conn = connectionFactory.GetEddsPerformanceConnection())
            {
                var result = (await conn.QueryFirstOrDefaultAsync <decimal?>(Resources.PoisonWait_ReadPoisonWaitsForHour,
                                                                             new { hour.HourTimeStamp, serverId }));
                return(result.HasValue && result.Value > 0);
            }
        }
        /// <inheritdoc />
        public TService GetService(TKey type)
        {
            ThrowOn.IsNull(type, $"key");

            if (this.typesToServices == null)
            {
                this.typesToServices = this.services.ToDictionary(GetServiceType, ml => ml);
            }

            if (this.typesToServices.ContainsKey(type) == false)
            {
                return(null);
            }

            return(this.typesToServices[type]);
        }
        public static byte[] GetResourceBytes(this Assembly assembly, string resourceName)
        {
            ThrowOn.IsNull(assembly, "assembly");
            ThrowOn.IsNull(resourceName, "resourceName");
            var result = new List <byte>();

            using (var stream = assembly.GetManifestResourceStream(resourceName))
            {
                ThrowOn.IsNull(resourceName, $"Couldn't find resource {resourceName} in assembly {assembly.FullName}. stream");

                var buffer = new byte[1028];
                while (stream.Read(buffer, 0, buffer.Length) > 0)
                {
                    result.AddRange(buffer);
                }

                return(result.ToArray());
            }
        }
        public async Task UpdateLatestVersion(Version executingVersion)
        {
            ThrowOn.IsNull(executingVersion, "executingVersion");

            // Init the table if it doesn't exist
            await this.pdbVersionRepository.InitializeIfNotExists();

            // Get the latest recorded version from the environment
            var installedVersion = await this.pdbVersionRepository.GetLatestVersionAsync();

            if (executingVersion < installedVersion)
            {
                throw new Exception($"Cannot update from version {installedVersion} to version {executingVersion}");
            }

            // Update it via repository
            await this.pdbVersionRepository.SetLatestVersionAsync(executingVersion);

            await this.logger.LogVerboseAsync($"Updated from version {installedVersion} to version {executingVersion}");
        }
        /// <inheritdoc />
        public async Task <IList <int> > ProcessBatch(int batchId)
        {
            // Query Batch
            var batch = this.searchAuditBatchRepository.ReadBatch(batchId);

            ThrowOn.IsNull(batch, "batch");

            // Check that this workspace exists before doing anything else
            if (!await this.serverRepository.ReadWorkspaceExistsAsync(batch.WorkspaceId) ||
                !await this.workspaceService.WorkspaceIsAvailableAsync(batch.WorkspaceId))
            {
                // Just mark the batch as completed.  The workspace was deleted after the batches were created.
                // Throw them out/ignore them and keep the process going.
                this.logger.LogWarning(
                    $"Workspace not found for batch ID ({batch.Id}), workspaceId ({batch.WorkspaceId}) not found.  For hourId {batch.HourId}, serverId {batch.ServerId}");
                batch.Completed = true;
                await this.searchAuditBatchRepository.UpdateAsync(batch);

                return(new List <int>());
            }

            // Process Batch
            // Grab the end hour
            var hour = await this.hourRepository.ReadAsync(batch.HourId);

            ThrowOn.IsNull(hour, "hour");

            // Grab the correct audit service (Sql/DataGrid)
            var repo = await this.workspaceAuditServiceFactory.GetAuditService(batch.WorkspaceId, batch.HourId);

            await this.logger.LogVerboseAsync(
                $"Getting Audits for hour: {batch.HourId} - {hour.HourTimeStamp} from auditService: {repo.GetType()}");

            // --- 28 (SEARCH) AUDITS ---
            // Read the search audits
            var audits = await repo.ReadAuditsAsync(
                batch.WorkspaceId,
                batch.HourId,
                new[] { AuditActionId.DocumentQuery },
                batch.BatchSize,
                batch.BatchStart);

            // group by query Id
            var searchAudits =
                audits.Select(a => new SearchAudit
            {
                Audit   = a,
                QueryId =
                    !string.IsNullOrEmpty(a.Details)
                                                        ? this.auditParsingService.ParseRawQueryId(a.Details)
                                                        : this.auditParsingService.ParseQueryId(a.ParsedDetails),
                QueryType =
                    !string.IsNullOrEmpty(a.Details)
                                                        ? this.auditParsingService.ParseRawQueryType(a.Details)
                                                        : this.auditParsingService.ParseQueryType(a.ParsedDetails)
            });

            var searchAuditGroups = searchAudits
                                    .GroupBy(sa => sa.QueryId)
                                    .SelectMany(sag =>
                                                string.IsNullOrEmpty(sag.Key)
                                        ? sag.Select(sa => new SearchAuditGroup {
                Audits = new List <SearchAudit> {
                    sa
                }
            })
                                        : new List <SearchAuditGroup>
            {
                new SearchAuditGroup
                {
                    Audits = sag.ToList()
                }
            });

            // analyze search audits
            var analyzeSearchAudits =
                (await searchAuditGroups.Select(a => this.searchAnalysisService.AnalyzeSearchAudit(a)).WhenAllStreamed()).ToList();

            // Save Report Data
            var reportTask = this.workspaceAuditReporter.ReportWorkspaceAudits(analyzeSearchAudits, hour, batch.ServerId);

            // Separate TotalLongRunningQueries / TotalComplexQueries / TotalQueries per user
            var results = this.auditBatchAnalyzer.GetBatchResults(analyzeSearchAudits, batchId);

            ThrowOn.IsNull(results, "batch results");

            // Save BatchResult
            using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
            {
                // Insert the BatchResult
                var createdResults = this.searchAuditBatchRepository.CreateBatchResults(results);
                ThrowOn.IsNull(createdResults, "created batch results");

                // Update HourSearchAuditBatch Status
                batch.Completed = true;
                await this.searchAuditBatchRepository.UpdateAsync(batch);

                // Make sure all of the above complete.  This should be a single point of failure.
                scope.Complete();

                // Await the reporter
                await reportTask;

                return(createdResults);
            }
        }
        public async Task HandleEvent(long eventId, EventSourceType eventType)
        {
            EventLock eventLock = null;

            try
            {
                // Grab the event
                var evnt = await this.eventRepository.ReadAsync(eventId);

                // if the event is not pending hangire then we wont process it. This can happen because of event migration or orphaned events.
                if (evnt.Status != EventStatus.PendingHangfire)
                {
                    this.logger.LogError($"Cannot process event {eventId} with status: {evnt.Status}");

                    // Mark the event errored (unless it's already errored, cancelled, or expired)
                    if (evnt.Status != EventStatus.Cancelled &&
                        evnt.Status != EventStatus.Error &&
                        evnt.Status != EventStatus.Expired)
                    {
                        await this.MarkEventErrored(eventId);
                    }

                    return;
                }

                // Add the event to the kernel context
                using (var eventKernel = this.eventChildKernelFactory.CreateChildKernel(evnt))
                {
                    // Try to put a lock on it
                    var currentWorker = await this.eventWorkerService.GetCurrentWorker();

                    ThrowOn.IsNull(currentWorker, "Event worker");
                    eventLock = await this.eventLockRepository.Claim(evnt, currentWorker.Id);

                    if (eventLock != null)
                    {
                        // If successful...
                        // Update to In Progress (from Hangfire Pending) and save
                        evnt.Status = EventStatus.InProgress;
                        await this.eventRepository.UpdateAsync(evnt);

                        // Grab the event task
                        var eventTask = this.eventTaskFactory.GetEventTask(eventKernel.Kernel, eventType);

                        // Process the event
                        var eventResult = await eventTask.ProcessEvent(evnt);

                        // Release the lock
                        await this.eventLockRepository.Release(eventLock);

                        await eventTask.MarkEventResultAsync(eventResult, evnt);

                        // Create the next events to call after this
                        await eventTask.CreateNextEvents(eventResult, evnt);
                    }
                    else
                    {
                        // If not successful, mark event as a duplicate and not execute
                        evnt.Status = EventStatus.Duplicate;
                        await this.eventRepository.UpdateAsync(evnt);
                    }
                }
            }
            catch (Exception ex)
            {
                this.logger.LogError($"Failed to run handleEvent: {eventId}", ex);

                // Attempt to mark the event errored
                await this.MarkEventErrored(eventId);

                // If we have a lock that we made, but failed after event execution
                if (eventLock != null && eventLock.EventId == eventId)
                {
                    // Attempt to release the lock
                    await this.eventLockRepository.Release(eventLock);
                }
            }
        }