/// <summary> /// Extracts a deploy anncouncement. /// </summary> /// <param name="announcement">The announcement that needs to be extracted.</param> /// <param name="token">Token of cancellation.</param> /// <inheritdoc /> /// <exception cref="AggregateException">Throw when one or more fusions failed to extract.</exception> public void Extract(IDeployAnnouncement announcement, CancellationToken token) { EnsureArg.IsNotNull(announcement, nameof(announcement)); var opts = new ParallelOptions { CancellationToken = token }; var fusionIds = announcement.GetFusionIds(); Parallel.ForEach(fusionIds, opts, (_, state) => { try { ExtractFusion(_, announcement); } catch (Exception ex) { state.Stop(); throw new FusionException(FusionException.ExtractionFailure, _, ex); } }); }
private void ExtractFusion(string fusionId, IDeployAnnouncement announcement) { EnsureArg.IsNotNullOrEmpty(fusionId, nameof(fusionId)); EnsureArg.IsNotNull(announcement, nameof(announcement)); var fusionConfig = GetFusionConfig(fusionId); var packageVersions = announcement .GetPackageVersions(fusionConfig.Id) .Stale(); packageVersionValidator .ConfirmAvailability(packageVersions); using (var packageStream = new MemoryStream()) { var fusion = fusionFactory .CreateNew(packageStream); try { fusionBuilder.Build(fusionConfig, fusion, packageVersions); } finally { (fusion as IDisposable)?.Dispose(); } using (var packageStreamReadable = new MemoryStream(packageStream.ToArray())) { fusionExtractor.Extract(fusionConfig, packageStreamReadable); } } }
/// <summary> /// Schedules an <see cref="IDeployAnnouncement"/>. /// </summary> /// <param name="announcement">The announcement that needs to be scheduled.</param> /// <param name="token">The token of cancellation.</param> /// <inheritdoc /> public async Task ScheduleAsync(IDeployAnnouncement announcement, CancellationToken token) { EnsureArg.IsNotNull(announcement, nameof(announcement)); var fusionIds = announcement .GetFusionIds() .OrderBy(_ => GetOrderId(_)) .Stale(); if (!isFullCompleted && announcement.IsDelta()) { throw new ScheduleException(ScheduleException.FullAnnouncementRequired, "*"); } await syncLock.WaitAsync(); try { var activeProcesses = GetActiveProcesses(fusionIds); await TerminateMultipleAsync(activeProcesses, token); // drains and stops the services logService.Info("Terminated all active fusion(s)."); fusionService.Extract(announcement, token); // extracts the new fusions logService.Info("Extracted all new fusion(s)."); var newProcesses = SpawnMultiple(fusionIds, token).Stale(); // spawns the services logService.Info("Spawned all new fusion(s)."); await WaitForAnnouncements(newProcesses, token); // wait for all port callbacks logService.Info("Received all announcements from the new fusion(s)."); await StartupMultipleAsync(newProcesses, token); // calls all the startups + nurse statusses logService.Info("Started all new fusion(s) and checked their patient(s)."); ResumeAll(token); logService.Info("Resumed all drainers, deployment completed."); if (!announcement.IsDelta()) { isFullCompleted = true; } } finally { syncLock.Release(); } }
/// <summary> /// Publishes the versions to the server. /// </summary> /// <param name="announcement">Announcement that needs to be published.</param> /// <param name="token">Token used to cancel the announcement.</param> /// <inheritDoc /> public async Task PublishAsync(IDeployAnnouncement announcement, CancellationToken token) { EnsureArg.IsNotNull(announcement, nameof(announcement)); var newPackageVersions = announcement .GetNewPackageVersions() .Stale(); if (!newPackageVersions.Any()) { return; } foreach (var version in newPackageVersions) { token.ThrowIfCancellationRequested(); await PublishAsync(version); } }