/// <summary> /// Start a bus, throwing an exception if the bus does not start in the specified timeout /// </summary> /// <param name="bus">The bus handle</param> /// <param name="startTimeout">The wait time before throwing an exception</param> public static void Start(this IBusControl bus, TimeSpan startTimeout) { using var cancellationTokenSource = new CancellationTokenSource(startTimeout); TaskUtil.Await(() => bus.StartAsync(cancellationTokenSource.Token), cancellationTokenSource.Token); }
public AsyncPipeContextAgent() { _context = TaskUtil.GetTask <TContext>(); _agent = new PipeContextAgent <TContext>(_context.Task); }
/// <summary> /// Starts a bus, throwing an exception if the bus does not start /// It is a wrapper of the async method `StartAsync` /// </summary> /// <param name="busControl">The bus handle</param> public static void Start(this IBusControl busControl) { TaskUtil.Await(() => busControl.StartAsync()); }
// 1 つのディレクトリをバックアップする public async Task DoSingleDirBackupAsync(string srcDir, string destDir, CancellationToken cancel = default, string?ignoreDirNames = null) { DateTimeOffset now = DateTimeOffset.Now; FileSystemEntity[]? srcDirEnum = null; string[] ignoreDirNamesList = ignoreDirNames._NonNull()._Split(StringSplitOptions.RemoveEmptyEntries, ",", ";"); FileMetadata?srcDirMetadata = null; bool noError = true; try { if (srcDir._IsSamei(destDir)) { throw new CoresException($"srcDir == destDir. Directory path: '{srcDir}'"); } srcDirMetadata = await Fs.GetDirectoryMetadataAsync(srcDir, cancel : cancel); srcDirEnum = (await Fs.EnumDirectoryAsync(srcDir, false, EnumDirectoryFlags.NoGetPhysicalSize, cancel)).OrderBy(x => x.Name, StrComparer.IgnoreCaseComparer).ToArray(); FileSystemEntity[] destDirEnum = new FileSystemEntity[0]; DirSuperBackupMetadata?destDirOldMetaData = null; DirSuperBackupMetadata destDirNewMetaData; // 宛先ディレクトリがすでに存在しているかどうか検査する if (await Fs.IsDirectoryExistsAsync(destDir, cancel)) { destDirEnum = await Fs.EnumDirectoryAsync(destDir, false, EnumDirectoryFlags.NoGetPhysicalSize, cancel); // 宛先ディレクトリに存在するメタデータファイルのうち最新のファイルを取得する destDirOldMetaData = await GetLatestMetaDataFileNameAsync(destDir, destDirEnum, cancel); } else { // 宛先ディレクトリがまだ存在していない場合は作成する await Fs.CreateDirectoryAsync(destDir, FileFlags.BackupMode | FileFlags.AutoCreateDirectory, cancel); } // 宛先ディレクトリの日付情報のみ属性書き込みする try { await Fs.SetFileMetadataAsync(destDir, srcDirMetadata.Clone(FileMetadataCopyMode.TimeAll), cancel); } catch { // 属性書き込みは失敗してもよい } // 新しいメタデータを作成する destDirNewMetaData = new DirSuperBackupMetadata(); destDirNewMetaData.FileList = new List <DirSuperBackupMetadataFile>(); destDirNewMetaData.TimeStamp = now; destDirNewMetaData.DirMetadata = srcDirMetadata; destDirNewMetaData.DirList = new List <string>(); // 元ディレクトリに存在するサブディレクトリ名一覧をメタデータに追記する foreach (var subDir in srcDirEnum.Where(x => x.IsDirectory && x.IsCurrentOrParentDirectory == false)) { // シンボリックリンクは無視する if (subDir.IsSymbolicLink == false) { // 無視リストのいずれにも合致しない場合のみ if (ignoreDirNamesList.Where(x => x._IsSamei(subDir.Name)).Any() == false) { destDirNewMetaData.DirList.Add(subDir.Name); } } } // 元ディレクトリに存在するファイルを 1 つずつバックアップする var fileEntries = srcDirEnum.Where(x => x.IsFile); RefInt concurrentNum = new RefInt(); AsyncLock SafeLock = new AsyncLock(); await TaskUtil.ForEachAsync(Options.NumThreads, fileEntries, async (srcFile, taskIndex, cancel) => { long?encryptedPhysicalSize = null; await Task.Yield(); string destFilePath = Fs.PathParser.Combine(destDir, srcFile.Name); if (Options.EncryptPassword._IsNullOrZeroLen() == false) { destFilePath += Consts.Extensions.CompressedXtsAes256; } FileMetadata?srcFileMetadata = null; concurrentNum.Increment(); try { srcFileMetadata = await Fs.GetFileMetadataAsync(srcFile.FullPath, cancel: cancel); // このファイルと同一のファイル名がすでに宛先ディレクトリに物理的に存在するかどうか確認する bool exists = await Fs.IsFileExistsAsync(destFilePath, cancel); bool fileChangedOrNew = false; if (exists) { // すでに宛先ディレクトリに存在する物理的なファイルのメタデータを取得する FileMetadata destExistsMetadata = await Fs.GetFileMetadataAsync(destFilePath, cancel: cancel); if (Options.EncryptPassword._IsNullOrZeroLen()) { // 暗号化なし // ファイルサイズを比較する if (destExistsMetadata.Size != srcFile.Size) { // ファイルサイズが異なる fileChangedOrNew = true; } } else { // 暗号化あり // 宛先ディレクトリのメタデータにファイル情報が存在し、そのメタデータ情報におけるファイルサイズが元ファイルと同じであり、 // かつそのメタデータ情報に記載されている EncryptedPhysicalSize が宛先ディレクトリにある物理ファイルと全く同一である // 場合は、宛先ファイルが正しく存在すると仮定する string tmp1 = Fs.PathParser.GetFileName(destFilePath); if ((destDirOldMetaData?.FileList.Where(x => x.EncrypedFileName._IsSamei(tmp1) && x.EncryptedPhysicalSize == destExistsMetadata.Size && x.MetaData.Size == srcFile.Size).Any() ?? false) == false) { // ファイルサイズが異なるとみなす fileChangedOrNew = true; } } // 日付を比較する。ただし宛先ディレクトリの物理的なファイルの日付は信用できないので、メタデータ上のファイルサイズと比較する if (destDirOldMetaData != null) { DirSuperBackupMetadataFile?existsFileMetadataFromDirMetadata = destDirOldMetaData.FileList.Where(x => x.FileName._IsSamei(srcFile.Name)).SingleOrDefault(); if (existsFileMetadataFromDirMetadata == null) { // メタデータ上に存在しない fileChangedOrNew = true; } else { if (existsFileMetadataFromDirMetadata.MetaData !.LastWriteTime !.Value.Ticks != srcFileMetadata.LastWriteTime !.Value.Ticks) { // 最終更新日時が異なる fileChangedOrNew = true; } } } else { // 宛先ディレクトリ上にメタデータがない fileChangedOrNew = true; } } else { // 新しいファイルである fileChangedOrNew = true; } string?oldFilePathToDelete = null; if (fileChangedOrNew) { // ファイルが新しいか、または更新された場合は、そのファイルをバックアップする // ただし、バックアップ先に同名のファイルがすでに存在する場合は、 // .old.xxxx.YYYYMMDD_HHMMSS.0123._backup_history のような形式でまだ存在しない連番に古いファイル名をリネームする if (exists) { using (await SafeLock.LockWithAwait(cancel)) { string yymmdd = Str.DateTimeToStrShort(DateTime.UtcNow); string newOldFileName; // 連番でかつ存在していないファイル名を決定する for (int i = 0; ; i++) { string newOldFileNameCandidate = $".old.{Fs.PathParser.GetFileName(destFilePath)}.{yymmdd}.{i:D4}{Consts.Extensions.DirSuperBackupHistory}"; if (srcDirEnum.Where(x => x.Name._IsSamei(newOldFileNameCandidate)).Any() == false) { if (await Fs.IsFileExistsAsync(Fs.PathParser.Combine(destDir, newOldFileNameCandidate), cancel) == false) { newOldFileName = newOldFileNameCandidate; break; } } } // 変更されたファイル名を ._backup_history ファイルにリネーム実行する string newOldFilePath = Fs.PathParser.Combine(destDir, newOldFileName); await WriteLogAsync(DirSuperBackupLogType.Info, Str.CombineStringArrayForCsv("FileRename", destFilePath, newOldFilePath)); await Fs.MoveFileAsync(destFilePath, newOldFilePath, cancel); oldFilePathToDelete = newOldFilePath; // 隠しファイルにする try { var meta = await Fs.GetFileMetadataAsync(newOldFilePath, cancel: cancel); if (meta.Attributes != null && meta.Attributes.Bit(FileAttributes.Hidden) == false) { FileMetadata meta2 = new FileMetadata(attributes: meta.Attributes.BitAdd(FileAttributes.Hidden)); await Fs.SetFileMetadataAsync(newOldFilePath, meta2, cancel); } } catch { } } } // ファイルをコピーする // 属性は、ファイルの日付情報のみコピーする await WriteLogAsync(DirSuperBackupLogType.Info, Str.CombineStringArrayForCsv("FileCopy", srcFile.FullPath, destFilePath)); FileFlags flags = FileFlags.BackupMode | FileFlags.Async; if (this.Options.Flags.Bit(DirSuperBackupFlags.BackupNoVerify) == false) { flags |= FileFlags.CopyFile_Verify; } await Fs.CopyFileAsync(srcFile.FullPath, destFilePath, new CopyFileParams(flags: flags, metadataCopier: new FileMetadataCopier(FileMetadataCopyMode.TimeAll), encryptOption: Options.EncryptPassword._IsNullOrZeroLen() ? EncryptOption.None : EncryptOption.Encrypt | EncryptOption.Compress, encryptPassword: Options.EncryptPassword, deleteFileIfVerifyFailed: true), cancel: cancel); try { if (Options.EncryptPassword._IsNullOrZeroLen() == false) { var newFileMetadata = await Fs.GetFileMetadataAsync(destFilePath, FileMetadataGetFlags.NoPhysicalFileSize, cancel); encryptedPhysicalSize = newFileMetadata.Size; } } catch { } if (Options.Flags.Bit(DirSuperBackupFlags.BackupMakeHistory) == false) { // History を残さない場合 // コピーに成功したので ._backup_history ファイルは削除する if (oldFilePathToDelete._IsNotZeroLen()) { try { await Fs.DeleteFileAsync(oldFilePathToDelete, flags: FileFlags.BackupMode | FileFlags.ForceClearReadOnlyOrHiddenBitsOnNeed, cancel); } catch { } } } Stat.Copy_NumFiles++; Stat.Copy_TotalSize += srcFile.Size; } else { if (Options.EncryptPassword._IsNullOrZeroLen() == false) { string tmp1 = Fs.PathParser.GetFileName(destFilePath); encryptedPhysicalSize = destDirOldMetaData?.FileList.Where(x => x.EncrypedFileName._IsSame(tmp1) && x.MetaData.Size == srcFile.Size).FirstOrDefault()?.EncryptedPhysicalSize; if (encryptedPhysicalSize.HasValue == false) { encryptedPhysicalSize = destDirOldMetaData?.FileList.Where(x => x.EncrypedFileName._IsSamei(tmp1) && x.MetaData.Size == srcFile.Size).FirstOrDefault()?.EncryptedPhysicalSize; } } Stat.Skip_NumFiles++; Stat.Skip_TotalSize += srcFile.Size; // ファイルの日付情報のみ更新する try { await Fs.SetFileMetadataAsync(destFilePath, srcFileMetadata.Clone(FileMetadataCopyMode.TimeAll), cancel); } catch { // ファイルの日付情報の更新は失敗してもよい } } } catch (Exception ex) { Stat.Error_NumFiles++; Stat.Error_TotalSize += srcFile.Size; // ファイル単位のエラー発生 await WriteLogAsync(DirSuperBackupLogType.Error, Str.CombineStringArrayForCsv("FileError", srcFile.FullPath, destFilePath, ex.Message)); noError = false; } finally { concurrentNum.Decrement(); } // このファイルに関するメタデータを追加する if (srcFileMetadata != null) { lock (destDirNewMetaData.FileList) { destDirNewMetaData.FileList.Add(new DirSuperBackupMetadataFile() { FileName = srcFile.Name, EncrypedFileName = Options.EncryptPassword._IsNullOrZeroLen() ? null : srcFile.Name + Consts.Extensions.CompressedXtsAes256, MetaData = srcFileMetadata, EncryptedPhysicalSize = encryptedPhysicalSize, }); } } }, cancel : cancel); // 新しいメタデータをファイル名でソートする destDirNewMetaData.FileList = destDirNewMetaData.FileList.OrderBy(x => x.FileName, StrComparer.IgnoreCaseComparer).ToList(); destDirNewMetaData.DirList = destDirNewMetaData.DirList.OrderBy(x => x, StrComparer.IgnoreCaseComparer).ToList(); // 新しいメタデータを書き込む string newMetadataFilePath = Fs.PathParser.Combine(destDir, $"{PrefixMetadata}{Str.DateTimeToStrShortWithMilliSecs(now.UtcDateTime)}{SuffixMetadata}"); await Fs.WriteJsonToFileAsync(newMetadataFilePath, destDirNewMetaData, FileFlags.BackupMode | FileFlags.OnCreateSetCompressionFlag, cancel : cancel); } catch (Exception ex) { Stat.Error_Dir++; noError = false; // ディレクトリ単位のエラー発生 await WriteLogAsync(DirSuperBackupLogType.Error, Str.CombineStringArrayForCsv("DirError1", srcDir, destDir, ex.Message)); } // 再度 宛先ディレクトリの日付情報のみ属性書き込みする (Linux の場合、中のファイルを更新するとディレクトリの日時が変ってしまうため) try { if (srcDirMetadata != null) { await Fs.SetFileMetadataAsync(destDir, srcDirMetadata.Clone(FileMetadataCopyMode.TimeAll), cancel); } } catch { // 属性書き込みは失敗してもよい } if (srcDirEnum != null) { bool ok = false; try { // ソースディレクトリの列挙に成功した場合は、サブディレクトリに対して再帰的に実行する foreach (var subDir in srcDirEnum.Where(x => x.IsDirectory && x.IsCurrentOrParentDirectory == false)) { // シンボリックリンクは無視する if (subDir.IsSymbolicLink == false) { // 無視リストのいずれにも合致しない場合のみ if (ignoreDirNamesList.Where(x => x._IsSamei(subDir.Name)).Any() == false) { await DoSingleDirBackupAsync(Fs.PathParser.Combine(srcDir, subDir.Name), Fs.PathParser.Combine(destDir, subDir.Name), cancel, ignoreDirNames); } } } ok = true; } catch (Exception ex) { // 何らかのディレクトリ単位のエラーで catch されていないものが発生 Stat.Error_Dir++; // ディレクトリ単位のエラー発生 await WriteLogAsync(DirSuperBackupLogType.Error, Str.CombineStringArrayForCsv("DirError2", srcDir, destDir, ex.Message)); } if (ok) { if (noError) { // ここまでの処理で何も問題がなければ (このディレクトリ内のすべてのファイルのコピーやメタデータの更新に成功しているなであれば) // Sync オプションが付与されている場合、不要なサブディレクトリとファイルを削除する if (this.Options.Flags.Bit(DirSuperBackupFlags.BackupSync)) { try { // 両方のディレクトリを再列挙いたします var srcDirEnum2 = (await Fs.EnumDirectoryAsync(srcDir, false, EnumDirectoryFlags.NoGetPhysicalSize, cancel)).OrderBy(x => x.Name, StrComparer.IgnoreCaseComparer).ToArray(); var destDirEnum2 = (await Fs.EnumDirectoryAsync(destDir, false, EnumDirectoryFlags.NoGetPhysicalSize, cancel)).OrderBy(x => x.Name, StrComparer.IgnoreCaseComparer).ToArray(); // 余分なファイルを削除いたします var extraFiles = destDirEnum2.Where(x => x.IsFile && x.IsSymbolicLink == false) .Where(x => x.Name._StartWithi(DirSuperBackup.PrefixMetadata) == false && x.Name._EndsWithi(DirSuperBackup.SuffixMetadata) == false) .Where(x => srcDirEnum2.Where(y => y.IsFile && y.Name._IsSameiTrim(x.Name)).Any() == false) .Where(x => srcDirEnum2.Where(y => y.IsFile && (y.Name + Consts.Extensions.CompressedXtsAes256)._IsSameiTrim(x.Name)).Any() == false); foreach (var extraFile in extraFiles) { string fullPath = Fs.PathParser.Combine(destDir, extraFile.Name); await WriteLogAsync(DirSuperBackupLogType.Info, Str.CombineStringArrayForCsv("DirSyncDeleteFile", fullPath)); try { await Fs.DeleteFileAsync(fullPath, FileFlags.BackupMode | FileFlags.ForceClearReadOnlyOrHiddenBitsOnNeed, cancel); Stat.SyncDelete_NumFiles++; } catch (Exception ex) { Stat.Error_NumDeleteFiles++; await WriteLogAsync(DirSuperBackupLogType.Error, Str.CombineStringArrayForCsv("DirSyncDeleteFileError", fullPath, ex.Message)); } } // 余分なサブディレクトリを削除いたします var extraSubDirs = destDirEnum2.Where(x => x.IsDirectory && x.IsCurrentOrParentDirectory == false && x.IsSymbolicLink == false) .Where(x => srcDirEnum2.Where(y => y.IsDirectory && y.IsCurrentOrParentDirectory == false && y.Name._IsSameiTrim(x.Name)).Any() == false); foreach (var extraSubDir in extraSubDirs) { string fullPath = Fs.PathParser.Combine(destDir, extraSubDir.Name); await WriteLogAsync(DirSuperBackupLogType.Info, Str.CombineStringArrayForCsv("DirSyncDeleteSubDir", fullPath)); try { await Fs.DeleteDirectoryAsync(fullPath, true, cancel); Stat.SyncDelete_NumDirs++; } catch (Exception ex) { Stat.Error_NumDeleteDirs++; await WriteLogAsync(DirSuperBackupLogType.Error, Str.CombineStringArrayForCsv("DirSyncDeleteSubDirError", fullPath, ex.Message)); } } } catch (Exception ex) { // 何らかのディレクトリ単位のエラーで catch されていないものが発生 Stat.Error_Dir++; // ディレクトリ単位のエラー発生 await WriteLogAsync(DirSuperBackupLogType.Error, Str.CombineStringArrayForCsv("DirSyncEnumError", srcDir, destDir, ex.Message)); } } } } } // 再度 宛先ディレクトリの日付情報のみ属性書き込みする (Linux の場合、中のファイルを更新するとディレクトリの日時が変ってしまうため) try { if (srcDirMetadata != null) { await Fs.SetFileMetadataAsync(destDir, srcDirMetadata.Clone(FileMetadataCopyMode.TimeAll), cancel); } } catch { // 属性書き込みは失敗してもよい } }
async Task ReadMainLoop(CancellationToken cancel) { try { var st = this.Reader.StreamReader; int numFailed = 0; while (true) { await TaskUtil.AwaitWithPollAsync(Timeout.Infinite, this.Emitter !.Options.Delay, () => this.Reader.StreamReader.IsReadyToRead(), cancel); IReadOnlyList <ReadOnlyMemory <byte> > dataToWrite = DequeueAll(out long totalSize, this.Emitter.Options.DefragmentWriteBlockSize); if (totalSize == 0) { if (cancel.IsCancellationRequested) { break; } else { continue; } } L_RETRY: try { await Emitter.EmitAsync(dataToWrite); numFailed = 0; if (this.Reader.StreamReader.IsReadyToRead() == false) { await Emitter.FlushAsync(); } } catch (Exception ex) { ex._Debug(); numFailed++; if (cancel.IsCancellationRequested == false) { await cancel._WaitUntilCanceledAsync(Util.GenRandIntervalWithRetry(CoresConfig.LazyWriteBufferSettings.ErrorRetryIntervalStd, numFailed, CoresConfig.LazyWriteBufferSettings.ErrorRetryIntervalMax)); goto L_RETRY; } else { break; } } } } finally { try { await Emitter !.CloseAsync(); } catch { } } }
public OneMessageConsumer() { _completed = TaskUtil.GetTask <MessageA>(); }
public virtual Task <TooltipInformation> GetTooltipInformation(CancellationToken token) { return(TaskUtil.Default <TooltipInformation> ()); }
public Task <TResult> Convert <T>(InitializeContext <T> context, TVariable input) where T : class { return(input?.GetValue(context) ?? TaskUtil.Default <TResult>()); }
public void Start() { TaskUtil.Await(() => _busControl.StartAsync()); }
/// <summary> /// 支线任务引导 /// </summary> /// <param name="button"></param> private void OnSubTaskButtonClick(GameObject button) { string trace = TaskUtil.GetTraceInfo(_taskMode.CurrentSubTaskVo); BaseDisplay display = TaskUtil.GetTaskDisplay(trace); MoveTo(display); }
/// <summary> /// 解析任务描述 /// </summary> /// <param name="taskVo"></param> /// <returns></returns> private string GetTaskDescribe(TaskVo taskVo) { return TaskUtil.GetTaskDescribe(taskVo); }
Task ModelContext.BasicAck(ulong deliveryTag, bool multiple) { return(_model.IsClosed ? TaskUtil.Faulted <bool>(new InvalidOperationException($"The channel was closed: {_model.CloseReason} {_model.ChannelNumber}")) : _executor.Run(() => _model.BasicAck(deliveryTag, multiple), CancellationToken)); }
public void ThenTheCompletedSagaIsNotUpdated() { var actual = TaskUtil.Await(() => SagaRepository.GetSaga(_correlationId)); Assert.That(actual.Version, Is.EqualTo(_simpleSaga.Version)); }
Task <TResult> IPropertyConverter <TResult, TInput> .Convert <TMessage>(InitializeContext <TMessage> context, TInput input) { return(_converter.TryConvert(input, out var result) ? Task.FromResult(result) : TaskUtil.Default <TResult>()); }
public PendingConfirmation(string exchange, ulong publishTag) { _exchange = exchange; PublishTag = publishTag; _source = TaskUtil.GetTask <ulong>(); }
public async Task TestDeadlockOnAcquire() { IEventLoop threadA1 = new DefaultEventLoop(); Bootstrap bootstrapA1 = new Bootstrap() .Channel <LocalChannel>().Group(threadA1).LocalAddress(new LocalAddress("A1")); IEventLoop threadA2 = new DefaultEventLoop(); Bootstrap bootstrapA2 = new Bootstrap() .Channel <LocalChannel>().Group(threadA2).LocalAddress(new LocalAddress("A2")); IEventLoop threadB1 = new DefaultEventLoop(); Bootstrap bootstrapB1 = new Bootstrap() .Channel <LocalChannel>().Group(threadB1).LocalAddress(new LocalAddress("B1")); IEventLoop threadB2 = new DefaultEventLoop(); Bootstrap bootstrapB2 = new Bootstrap() .Channel <LocalChannel>().Group(threadB2).LocalAddress(new LocalAddress("B2")); FixedChannelPool poolA1 = new FixedChannelPool(bootstrapA1, NoopHandler.Instance, 1); FixedChannelPool poolA2 = new FixedChannelPool(bootstrapB2, NoopHandler.Instance, 1); FixedChannelPool poolB1 = new FixedChannelPool(bootstrapB1, NoopHandler.Instance, 1); FixedChannelPool poolB2 = new FixedChannelPool(bootstrapA2, NoopHandler.Instance, 1); // Synchronize threads on these barriers to ensure order of execution, first wait until each thread is inside // the newPool callbak, then hold the two threads that should lose the match until the first two returns, then // release them to test if they deadlock when trying to release their pools on each other's threads. Barrier arrivalBarrier = new Barrier(4); Barrier releaseBarrier = new Barrier(3); var channelPoolMap = new TestChannelPoolMap0( threadA1, threadA2, threadB1, threadB2, poolA1, poolA2, poolB1, poolB2, arrivalBarrier, releaseBarrier); // Thread A1 calls ChannelPoolMap.get(A) // Thread A2 calls ChannelPoolMap.get(A) // Thread B1 calls ChannelPoolMap.get(B) // Thread B2 calls ChannelPoolMap.get(B) var futureA1 = threadA1.SubmitAsync(() => { return(channelPoolMap.Get("A")); }); var futureA2 = threadA2.SubmitAsync(() => { return(channelPoolMap.Get("A")); }); var futureB1 = threadB1.SubmitAsync(() => { return(channelPoolMap.Get("B")); }); var futureB2 = threadB2.SubmitAsync(() => { return(channelPoolMap.Get("B")); }); // Thread A1 succeeds on updating the map and moves on // Thread B1 succeeds on updating the map and moves on // These should always succeed and return with new pools try { var result = await TaskUtil.WaitAsync(futureA1, TimeSpan.FromSeconds(1)); if (!result || !futureA1.IsSuccess()) { throw new TimeoutException(); } Assert.Same(poolA1, futureA1.Result); result = await TaskUtil.WaitAsync(futureB1, TimeSpan.FromSeconds(1)); if (!result || !futureB1.IsSuccess()) { throw new TimeoutException(); } Assert.Same(poolB1, futureB1.Result); } catch (Exception) { Shutdown(threadA1, threadA2, threadB1, threadB2); throw; } // Now release the other two threads which at this point lost the race and will try to clean up the acquired // pools. The expected scenario is that both pools close, in case of a deadlock they will hang. if (!releaseBarrier.SignalAndWait(TimeSpan.FromSeconds(1))) { Assert.False(true); } // Thread A2 fails to update the map and submits close to thread B2 // Thread B2 fails to update the map and submits close to thread A2 // If the close is blocking, then these calls will time out as the threads are waiting for each other // If the close is not blocking, then the previously created pools will be returned try { var result = await TaskUtil.WaitAsync(futureA2, TimeSpan.FromSeconds(1)); if (!result || !futureA2.IsSuccess()) { throw new TimeoutException(); } Assert.Same(poolA1, futureA2.Result); result = await TaskUtil.WaitAsync(futureB2, TimeSpan.FromSeconds(1)); if (!result || !futureB2.IsSuccess()) { throw new TimeoutException(); } Assert.Same(poolB1, futureB2.Result); } catch (TimeoutException) { Assert.False(true); // Fail the test on timeout to distinguish from other errors throw; } finally { poolA1.Close(); poolA2.Close(); poolB1.Close(); poolB2.Close(); channelPoolMap.Close(); Shutdown(threadA1, threadA2, threadB1, threadB2); } }
BusHandle IBusControl.Start() { if (_busHandle != null) { _log.Warn($"The bus was already started, additional Start attempts are ignored: {Address}"); return(_busHandle); } TaskUtil.Await(() => _busObservable.PreStart(this)); Exception exception = null; var endpoints = new List <ReceiveEndpointHandle>(); var hosts = new List <HostHandle>(); var observers = new List <ConnectHandle>(); var busReady = new BusReady(_receiveEndpoints); try { if (_log.IsDebugEnabled) { _log.DebugFormat("Starting bus hosts..."); } foreach (IBusHostControl host in _hosts) { try { HostHandle hostHandle = host.Start(); hosts.Add(hostHandle); } catch (Exception ex) { exception = ex; } } if (_log.IsDebugEnabled) { _log.DebugFormat("Starting receive endpoints..."); } foreach (IReceiveEndpoint endpoint in _receiveEndpoints) { try { ConnectHandle observerHandle = endpoint.ConnectReceiveObserver(_receiveObservers); observers.Add(observerHandle); ReceiveEndpointHandle handle = endpoint.Start(); endpoints.Add(handle); } catch (Exception ex) { exception = ex; } } } catch (Exception ex) { exception = ex; } if (exception != null) { try { var handle = new Handle(hosts, endpoints, observers, this, _busObservable, busReady); handle.Stop(TimeSpan.FromSeconds(60)); } catch (Exception ex) { _log.Error("Failed to stop partially created bus", ex); } TaskUtil.Await(() => _busObservable.StartFaulted(this, exception)); throw new MassTransitException("The service bus could not be started.", exception); } _busHandle = new Handle(hosts, endpoints, observers, this, _busObservable, busReady); TaskUtil.Await(() => _busObservable.PostStart(this, busReady.Ready)); return(_busHandle); }
public async Task TestDeadlockOnRemove() { IEventLoop thread1 = new DefaultEventLoop(); Bootstrap bootstrap1 = new Bootstrap() .Channel <LocalChannel>().Group(thread1).LocalAddress(new LocalAddress("#1")); IEventLoop thread2 = new DefaultEventLoop(); Bootstrap bootstrap2 = new Bootstrap() .Channel <LocalChannel>().Group(thread2).LocalAddress(new LocalAddress("#2")); // pool1 runs on thread2, pool2 runs on thread1 FixedChannelPool pool1 = new FixedChannelPool(bootstrap2, NoopHandler.Instance, 1); FixedChannelPool pool2 = new FixedChannelPool(bootstrap1, NoopHandler.Instance, 1); var channelPoolMap = new TestChannelPoolMap1(pool1, pool2); Assert.Same(pool1, channelPoolMap.Get("#1")); Assert.Same(pool2, channelPoolMap.Get("#2")); // thread1 tries to remove pool1 which is running on thread2 // thread2 tries to remove pool2 which is running on thread1 var barrier = new Barrier(2); var future1 = thread1.SubmitAsync(() => { if (!barrier.SignalAndWait(TimeSpan.FromSeconds(1))) { throw new TimeoutException(); } channelPoolMap.Remove("#1"); return(1); }); var future2 = thread2.SubmitAsync(() => { if (!barrier.SignalAndWait(TimeSpan.FromSeconds(1))) { throw new TimeoutException(); } channelPoolMap.Remove("#2"); return(2); }); // A blocking close on remove will cause a deadlock here and the test will time out try { var result = await TaskUtil.WaitAsync(future1, TimeSpan.FromSeconds(1)); if (!result || !future1.IsSuccess()) { throw new TimeoutException(); } result = await TaskUtil.WaitAsync(future2, TimeSpan.FromSeconds(1)); if (!result || !future2.IsSuccess()) { throw new TimeoutException(); } } catch (TimeoutException) { Assert.False(true); // Fail the test on timeout to distinguish from other errors } finally { pool1.Close(); pool2.Close(); channelPoolMap.Close(); Shutdown(thread1, thread2); } }
public ReceiveEndpointDependency(IReceiveEndpointObserverConnector connector) { _ready = TaskUtil.GetTask <ReceiveEndpointReady>(); _handle = connector.ConnectReceiveEndpointObserver(this); }
public void Run(CancellationToken cancellationToken = default(CancellationToken)) { _capture = new MessageMetricCapture(_settings.MessageCount); var busControl = _transport.GetBusControl(ConfigureReceiveEndpoint); _client = busControl.CreateRequestClient <RequestMessage>(_transport.TargetEndpointAddress, _settings.RequestTimeout); try { Console.WriteLine("Running Request Response Benchmark"); TaskUtil.Await(() => RunBenchmark(), cancellationToken); Console.WriteLine("Message Count: {0}", _settings.MessageCount); Console.WriteLine("Clients: {0}", _settings.Clients); Console.WriteLine("Durable: {0}", _settings.Durable); Console.WriteLine("Prefetch Count: {0}", _settings.PrefetchCount); Console.WriteLine("Concurrency Limit: {0}", _settings.ConcurrencyLimit); Console.WriteLine("Total consume duration: {0:g}", _consumeDuration); Console.WriteLine("Consume message rate: {0:F2} (msg/s)", _settings.MessageCount * 1000 / _consumeDuration.TotalMilliseconds); Console.WriteLine("Total request duration: {0:g}", _requestDuration); Console.WriteLine("Request rate: {0:F2} (msg/s)", _settings.MessageCount * 1000 / _requestDuration.TotalMilliseconds); Console.WriteLine("Concurrent Consumer Count: {0}", RequestConsumer.MaxConsumerCount); MessageMetric[] messageMetrics = _capture.GetMessageMetrics(); Console.WriteLine("Avg Request Time: {0:F0}ms", messageMetrics.Average(x => x.RequestLatency) * 1000 / Stopwatch.Frequency); Console.WriteLine("Min Request Time: {0:F0}ms", messageMetrics.Min(x => x.RequestLatency) * 1000 / Stopwatch.Frequency); Console.WriteLine("Max Request Time: {0:F0}ms", messageMetrics.Max(x => x.RequestLatency) * 1000 / Stopwatch.Frequency); Console.WriteLine("Med Request Time: {0:F0}ms", messageMetrics.Median(x => x.RequestLatency) * 1000 / Stopwatch.Frequency); Console.WriteLine("95t Request Time: {0:F0}ms", messageMetrics.Percentile(x => x.RequestLatency) * 1000 / Stopwatch.Frequency); Console.WriteLine("Avg Consume Time: {0:F0}ms", messageMetrics.Average(x => x.ConsumeLatency) * 1000 / Stopwatch.Frequency); Console.WriteLine("Min Consume Time: {0:F0}ms", messageMetrics.Min(x => x.ConsumeLatency) * 1000 / Stopwatch.Frequency); Console.WriteLine("Max Consume Time: {0:F0}ms", messageMetrics.Max(x => x.ConsumeLatency) * 1000 / Stopwatch.Frequency); Console.WriteLine("Med Consume Time: {0:F0}ms", messageMetrics.Median(x => x.ConsumeLatency) * 1000 / Stopwatch.Frequency); Console.WriteLine("95t Consume Time: {0:F0}ms", messageMetrics.Percentile(x => x.ConsumeLatency) * 1000 / Stopwatch.Frequency); Console.WriteLine(); Console.WriteLine("Request duration distribution"); DrawResponseTimeGraph(messageMetrics, x => x.RequestLatency); } finally { busControl.Stop(); } }
// 1 つのディレクトリを復元する public async Task DoSingleDirRestoreAsync(string srcDir, string destDir, CancellationToken cancel = default, string?ignoreDirNames = null) { DateTimeOffset now = DateTimeOffset.Now; FileSystemEntity[]? srcDirEnum = null; string[] ignoreDirNamesList = ignoreDirNames._NonNull()._Split(StringSplitOptions.RemoveEmptyEntries, ",", ";"); try { if (srcDir._IsSamei(destDir)) { throw new CoresException($"srcDir == destDir. Directory path: '{srcDir}'"); } // 元ディレクトリが存在していることを確認する if (await Fs.IsDirectoryExistsAsync(srcDir, cancel) == false) { throw new CoresException($"The directory '{srcDir}' not found."); } // 元ディレクトリを列挙する srcDirEnum = (await Fs.EnumDirectoryAsync(srcDir, false, EnumDirectoryFlags.NoGetPhysicalSize, cancel)).OrderBy(x => x.Name, StrComparer.IgnoreCaseComparer).ToArray(); // 元ディレクトリに存在するメタデータファイルのうち最新のファイルを取得する // なお、メタデータファイルのパースがエラーになったら、必ずエラーを発生し中断する DirSuperBackupMetadata?dirMetaData = await GetLatestMetaDataFileNameAsync(srcDir, srcDirEnum, cancel, throwJsonParseError : true) !; if (dirMetaData == null) { throw new CoresException($"Metadata not found on the directory '{srcDir}'."); } // 先ディレクトリがまだ存在していない場合は作成をする if (await Fs.IsDirectoryExistsAsync(destDir, cancel) == false) { FileFlags newDirFlags = FileFlags.None; // ディレクトリの圧縮フラグを適切に設定する if (dirMetaData.DirMetadata.SpecialOperationFlags.Bit(FileSpecialOperationFlags.SetCompressionFlag) || (dirMetaData.DirMetadata.Attributes?.Bit(FileAttributes.Compressed) ?? false)) { newDirFlags |= FileFlags.OnCreateSetCompressionFlag; } else { newDirFlags |= FileFlags.OnCreateRemoveCompressionFlag; } try { await Fs.CreateDirectoryAsync(destDir, newDirFlags, cancel); } catch { // ヘンな圧縮フラグの設定に失敗した場合もう一度作成試行する try { await Fs.CreateDirectoryAsync(destDir, FileFlags.None, cancel); } catch { // ディレクトリ作成コマンドでなぜかエラーになっても、結果としてディレクトリが作成されればそれでよい if (await Fs.IsDirectoryExistsAsync(destDir, cancel) == false) { throw; } // やはりディレクトリの作成に失敗したらここでエラーを発生させる } } } // ディレクトリの属性を設定する try { var newDirMetadata = dirMetaData.DirMetadata; if (Options.Flags.Bit(DirSuperBackupFlags.RestoreNoAcl)) { newDirMetadata.Security = null; } await Fs.SetDirectoryMetadataAsync(destDir, newDirMetadata, cancel); } catch (Exception ex) { // ディレクトリの属性の設定に失敗したが、軽微なエラーなのでエラーを出して続行する await WriteLogAsync(DirSuperBackupLogType.Error, Str.CombineStringArrayForCsv("DirAttributeSetError", srcDir, destDir, ex.Message)); Stat.Error_Dir++; } // 元ディレクトリに存在するはずのファイル (メタデータに書いてある) を 1 つずつ復元する RefInt concurrentNum = new RefInt(); AsyncLock SafeLock = new AsyncLock(); await TaskUtil.ForEachAsync(Options.NumThreads, dirMetaData.FileList, async (srcFile, taskIndex, cancel) => { await Task.Yield(); string srcFilePath = Fs.PathParser.Combine(srcDir, srcFile.FileName); string destFilePath = Fs.PathParser.Combine(destDir, srcFile.FileName); FileMetadata?srcFileMetadata = null; concurrentNum.Increment(); try { bool isEncrypted = false; string encryptPassword = ""; if (srcFile.EncrypedFileName._IsNullOrZeroLen() == false) { srcFilePath = Fs.PathParser.Combine(srcDir, srcFile.EncrypedFileName); // 暗号化ファイルである if (Options.EncryptPassword._IsNullOrZeroLen()) { // パスワードが指定されていない throw new CoresException($"The file '{srcFilePath}' is encrypted, but no password is specified."); } isEncrypted = true; encryptPassword = this.Options.EncryptPassword; } srcFileMetadata = srcFile.MetaData; // このファイルと同一の先ファイル名がすでに宛先ディレクトリに物理的に存在するかどうか確認する bool exists = await Fs.IsFileExistsAsync(destFilePath, cancel); bool restoreThisFile = false; if (exists) { // すでに宛先ディレクトリに存在する物理的なファイルのメタデータを取得する FileMetadata destExistsMetadata = await Fs.GetFileMetadataAsync(destFilePath, cancel: cancel); if (Options.Flags.Bit(DirSuperBackupFlags.RestoreOnlyNewer) == false) { // 古いファイルも復元する if (Options.Flags.Bit(DirSuperBackupFlags.RestoreDoNotSkipExactSame)) { // 必ず上書きする restoreThisFile = true; } else { // ファイルサイズを比較する if (destExistsMetadata.Size != srcFileMetadata.Size) { // ファイルサイズが異なる restoreThisFile = true; } // 日付を比較する if (srcFileMetadata !.LastWriteTime !.Value.Ticks != destExistsMetadata.LastWriteTime !.Value.Ticks) { // 最終更新日時が異なる restoreThisFile = true; } if (restoreThisFile == false) { // 新旧両方のファイルが存在する場合で、ファイルサイズも日付も同じであれば、復元先ファイル内容がバックアップファイルと同一かチェックし、同一の場合はコピーをスキップする ResultOrError <int> sameRet; if (isEncrypted == false) { sameRet = await FileUtil.CompareFileHashAsync(new FilePath(srcFilePath, Fs, flags: FileFlags.BackupMode), new FilePath(destFilePath, Fs, flags: FileFlags.BackupMode), cancel: cancel); } else { sameRet = await FileUtil.CompareEncryptedFileHashAsync(encryptPassword, true, new FilePath(destFilePath, Fs, flags: FileFlags.BackupMode), new FilePath(srcFilePath, Fs, flags: FileFlags.BackupMode), cancel: cancel); } if (sameRet.IsOk == false || sameRet.Value != 0) { restoreThisFile = true; } } } } else { // バックアップのほうが新しい場合のみ復元するモード // 日付を比較する if (srcFileMetadata !.LastWriteTime !.Value.Ticks > destExistsMetadata.LastWriteTime !.Value.Ticks) { // 最終更新日時がバックアップのほうが新しい restoreThisFile = true; } } } else { restoreThisFile = true; } if (restoreThisFile) { // すべての判断に合格したら、このファイルの復元を実施する if (exists) { if (Options.Flags.Bit(DirSuperBackupFlags.RestoreMakeBackup)) { // 復元先に同名のファイルがすでに存在する場合は、 // .original.xxxx.0123.original のような形式でまだ存在しない連番に古いファイル名をリネームする using (await SafeLock.LockWithAwait(cancel)) { string newOldFileName; // 連番でかつ存在していないファイル名を決定する for (int i = 0; ; i++) { string newOldFileNameCandidate = $".original.{srcFile.FileName}.{i:D4}.original"; if (await Fs.IsFileExistsAsync(Fs.PathParser.Combine(destDir, newOldFileNameCandidate), cancel) == false) { newOldFileName = newOldFileNameCandidate; break; } } // 変更されたファイル名を .old ファイルにリネーム実行する string newOldFilePath = Fs.PathParser.Combine(destDir, newOldFileName); await WriteLogAsync(DirSuperBackupLogType.Info, Str.CombineStringArrayForCsv("FileRename", destFilePath, newOldFilePath)); await Fs.MoveFileAsync(destFilePath, newOldFilePath, cancel); // 隠しファイルにする try { var meta = await Fs.GetFileMetadataAsync(newOldFilePath, cancel: cancel); if (meta.Attributes != null) { FileMetadata meta2 = new FileMetadata(attributes: meta.Attributes?.BitAdd(FileAttributes.Hidden)); await Fs.SetFileMetadataAsync(newOldFilePath, meta2, cancel); } } catch { } } } } // 復元メイン await WriteLogAsync(DirSuperBackupLogType.Info, Str.CombineStringArrayForCsv("FileCopy", srcFilePath, destFilePath)); FileFlags flags = FileFlags.BackupMode | FileFlags.Async; if (this.Options.Flags.Bit(DirSuperBackupFlags.RestoreNoVerify) == false) { flags |= FileFlags.CopyFile_Verify; } // ファイルをコピーする await Fs.CopyFileAsync(srcFilePath, destFilePath, new CopyFileParams(flags: flags, metadataCopier: new FileMetadataCopier(FileMetadataCopyMode.TimeAll), encryptOption: isEncrypted ? EncryptOption.Decrypt | EncryptOption.Compress : EncryptOption.None, encryptPassword: encryptPassword), cancel: cancel, newFileMeatadata: Options.Flags.Bit(DirSuperBackupFlags.RestoreNoAcl) ? null : srcFileMetadata); Stat.Copy_NumFiles++; Stat.Copy_TotalSize += srcFile.MetaData.Size; // メタデータを再度復元 try { var meta = Options.Flags.Bit(DirSuperBackupFlags.RestoreNoAcl) ? srcFileMetadata.Clone(FileMetadataCopyMode.TimeAll | FileMetadataCopyMode.Attributes | FileMetadataCopyMode.ReplicateArchiveBit | FileMetadataCopyMode.AlternateStream | FileMetadataCopyMode.Author) : srcFileMetadata; await Fs.SetFileMetadataAsync(destFilePath, meta, cancel); } catch (Exception ex) { FileMetadata?existingFileMetadata = null; try { existingFileMetadata = await Fs.GetFileMetadataAsync(destFilePath, cancel: cancel); } catch { } if ((existingFileMetadata?.Attributes?.Bit(FileAttributes.ReadOnly) ?? true) == false) { // メタデータの属性の設定に失敗したが、軽微なエラーなのでエラーを出して続行する // (宛先ファイルが ReadOnly の場合は、この操作はエラーとなる可能性が高い。このような場合は、予期されている動作なので、エラーは表示しない) await WriteLogAsync(DirSuperBackupLogType.Error, Str.CombineStringArrayForCsv("FileAttributeSetError", srcFilePath, destFilePath, ex.Message)); Stat.Error_NumFiles++; } } } else { Stat.Skip_NumFiles++; Stat.Skip_TotalSize += srcFile.MetaData.Size; } } catch (Exception ex) { Stat.Error_NumFiles++; Stat.Error_TotalSize += srcFileMetadata?.Size ?? 0; // ファイル単位のエラー発生 await WriteLogAsync(DirSuperBackupLogType.Error, Str.CombineStringArrayForCsv("FileError", srcFilePath, destFilePath, ex.Message)); } finally { concurrentNum.Decrement(); } }); // このディレクトリの全ファイルの復元が終わったら、ディレクトリのタイムスタンプ情報を再書き込みする // (中のファイルが新しくなったことが原因で、ディレクトリの更新日時が新しくなってしまう可能性があるためである) try { await Fs.SetFileMetadataAsync(destDir, dirMetaData.DirMetadata.Clone(FileMetadataCopyMode.TimeAll), cancel); } catch { // 属性書き込みは失敗してもよい } try { // ソースディレクトリの列挙に成功した場合は、サブディレクトリに対して再帰的に実行する foreach (var subDir in dirMetaData.DirList) { // 無視リストのいずれにも合致しない場合のみ if (ignoreDirNamesList.Where(x => x._IsSamei(subDir)).Any() == false) { await DoSingleDirRestoreAsync(Fs.PathParser.Combine(srcDir, subDir), Fs.PathParser.Combine(destDir, subDir), cancel, ignoreDirNames); } } } catch (Exception ex) { // 何らかのディレクトリ単位のエラーで catch されていないものが発生 Stat.Error_Dir++; // ディレクトリ単位のエラー発生 await WriteLogAsync(DirSuperBackupLogType.Error, Str.CombineStringArrayForCsv("DirError1", srcDir, destDir, ex.Message)); } // 再度 宛先ディレクトリの日付情報のみ属性書き込みする (Linux の場合、中のファイルを更新するとディレクトリの日時が変ってしまうため) try { if (dirMetaData != null) { await Fs.SetFileMetadataAsync(destDir, dirMetaData.DirMetadata.Clone(FileMetadataCopyMode.TimeAll), cancel); } } catch { // 属性書き込みは失敗してもよい } } catch (Exception ex) { Stat.Error_Dir++; // ディレクトリ単位のエラー発生 await WriteLogAsync(DirSuperBackupLogType.Error, Str.CombineStringArrayForCsv("DirError2", srcDir, destDir, ex.Message)); } }
public TaskModule() : base("Task") { //任务列表 Get["/"] = r => { return(View["Grid"]); }; //任务编辑界面 Get["/Edit"] = r => { return(View["Edit"]); }; #region "取数接口API" //立即运行一次任务 Get["/Run/{Id}"] = r => { //取出单条记录数据 string TaskId = r.Id; JsonBaseModel <string> result = new JsonBaseModel <string>(); try { TaskHelper.RunById(TaskId); } catch (Exception ex) { result.HasError = true; result.Message = ex.Message; } return(Response.AsJson(result)); }; Get["/GetById/{Id}"] = r => { JsonBaseModel <TaskUtil> result = new JsonBaseModel <TaskUtil>(); try { //取出单条记录数据 string TaskId = r.Id; result.Result = TaskHelper.GetById(TaskId); } catch (Exception ex) { result.HasError = true; result.Message = ex.Message; } return(Response.AsJson(result)); }; //列表查询接口 Post["/PostQuery"] = r => { QueryCondition condition = this.Bind <QueryCondition>(); return(Response.AsJson(TaskHelper.Query(condition))); }; //保存数据 Post["/"] = r => { TaskUtil TaskUtil = this.Bind <TaskUtil>(); return(Response.AsJson(TaskHelper.SaveTask(TaskUtil))); }; //更新数据 Put["/"] = r => { TaskUtil TaskUtil = this.Bind <TaskUtil>(); return(Response.AsJson(TaskHelper.SaveTask(TaskUtil))); }; //删除任务接口 Delete["/{Id}"] = r => { JsonBaseModel <string> result = new JsonBaseModel <string>(); try { string TaskId = r.Id; TaskHelper.DeleteById(TaskId); } catch (Exception ex) { result.HasError = true; result.Message = ex.Message; } return(Response.AsJson(result)); }; //更新任务运行状态 Put["/{Id}/{Status:int}"] = r => { JsonBaseModel <string> result = new JsonBaseModel <string>(); try { TaskStatus Status = Enum.ToObject(typeof(TaskStatus), r.Status); string TaskId = r.Id; TaskHelper.UpdateTaskStatus(TaskId, Status); } catch (Exception ex) { result.HasError = true; result.Message = ex.Message; } return(Response.AsJson(result)); }; #endregion }
public void Kill() { TaskUtil.Await(() => SagaRepository.DeleteSaga(_saga.CorrelationId)); }
protected override async Task GetValueAsync(SortedDictionary <string, string> ret, RefInt nextPollingInterval, CancellationToken cancel = default) { SnmpWorkSettings settings = Host.Settings; if (settings.PingTargets._IsSamei("none") || settings.PingTargets._IsSamei("null")) { return; } string[] pingTargets = settings.PingTargets._Split(StringSplitOptions.RemoveEmptyEntries, ","); KeyValueList <string, IPAddress> kvList = new KeyValueList <string, IPAddress>(); // 名前解決 foreach (string pingTarget in pingTargets) { cancel.ThrowIfCancellationRequested(); try { ParseTargetString(pingTarget, out string hostname, out string alias); IPAddress ip = await LocalNet.GetIpAsync(hostname, cancel : cancel); kvList.Add(alias, ip); } catch (Exception ex) { ex._Debug(); } } List <Task <double> > taskList = new List <Task <double> >(); int interval = 0; int count = 3; // SpeedTest が動作中の場合は SpeedTest が完了するまで待機する numPerform++; if (numPerform >= 2) { interval = settings.PktLossIntervalMsec; count = settings.PktLossTryCount; await TaskUtil.AwaitWithPollAsync(Timeout.Infinite, 10, () => !SpeedTestClient.IsInProgress, cancel); } // 並列実行の開始 foreach (var kv in kvList) { taskList.Add(PerformOneAsync(kv.Value, count, settings.PktLossTimeoutMsecs, interval, cancel)); } // すべて終了するまで待機し、結果を整理 for (int i = 0; i < kvList.Count; i++) { var kv = kvList[i]; var task = taskList[i]; double lossRate = await task._TryAwait(); double quality = 1.0 - lossRate; quality = Math.Max(quality, 0.0); quality = Math.Min(quality, 1.0); ret.TryAdd($"{kv.Key}", ((double)quality * 100.0).ToString("F3")); } }
async Task DialogSessionMainProcAsync(DialogSession session, CancellationToken cancel) { session.Debug("Start"); ThinClientConnectOptions connectOptions = (ThinClientConnectOptions)session.Param !; await using WideTunnel wt = new WideTunnel(this.Options.WideTunnelOptions); ThinClientAuthResponse authResponseCache = null !; session.Debug($"Begin DcConnectEx. connectOptions: {connectOptions._GetObjectDump()}"); await using ThinClientConnection firstConnection = await DcConnectEx(wt, connectOptions, cancel, true, true, async (req, c) => { // 認証コールバック var response = (ThinClientAuthResponse)(await session.RequestAndWaitResponseAsync(req, Consts.ThinClient.RequestHardTimeoutMsecs, Consts.ThinClient.RequestSoftTimeoutMsecs, cancel)); authResponseCache = response; return(response); }, async (req, c) => { // OTP コールバック var response = (ThinClientOtpResponse)(await session.RequestAndWaitResponseAsync(req, Consts.ThinClient.RequestHardTimeoutMsecs, Consts.ThinClient.RequestSoftTimeoutMsecs, cancel)); return(response); }, async (req, c) => { // 検疫・MAC アドレスコールバック var response = (ThinClientInspectResponse)(await session.RequestAndWaitResponseAsync(req, Consts.ThinClient.RequestHardTimeoutMsecs, Consts.ThinClient.RequestSoftTimeoutMsecs, cancel)); return(response); }); //if (connectOptions.DebugGuacMode == false) //{ // session.Debug("Switching to WebSocket mode..."); // string webSocketUrl = await firstConnection.Socket.RequestSwitchToWebSocketAsync(cancel, Consts.ThinClient.RequestSwitchToWebSocketTimeoutMsecs); // session.Debug($"Switching to WebSocket mode OK. webSocketUrl = {webSocketUrl}"); //} session.Debug("First WideTunnel Connected."); if (connectOptions.DebugGuacMode == false) { // ThinGate ネイティブ WebSocket モード (ThinGate が WebSocket を直接話す) if (firstConnection.Caps.Bit(ThinServerCaps.GuacdSupported) == false) { // 古いバージョンであり、サポートされていない throw new VpnException(VpnError.ERR_DESK_GUACD_NOT_SUPPORTED_VER); } // 'A' を送信 // この段階でサーバー機の Guacd にソケットが接続された状態となる byte[] a = new byte[] { (byte)'A' }; await firstConnection.Stream.SendAsync(a, cancel); // 最初に少し Guacamole Protocol で ThinWebClient と guacd との間で対話を行なう。 // これを行なうことにより、guacd が、local PC の RDP/VNC に接続し通信を初期化する。 // その後、WebSocket への切替えを行ない、それ以降は guacd とクライアント Web ブラウザが直接対話する。 await using var guaClient = new GuaClient( new GuaClientSettings( "", 0, firstConnection.SvcType == ThinSvcType.Rdp ? GuaProtocol.Rdp : GuaProtocol.Vnc, "127.0.0.1", firstConnection.SvcPort, connectOptions.GuaPreference !, connectOptions.IsWebpSupported, firstConnection.Caps.Bit(ThinServerCaps.AudioInSupported)), firstConnection.Stream); string webSocketUrl = ""; // この非同期 StartAsync は、Guacd Protocol で "select, rdp" のような最初の hello に相当するプロトコルを送付し、 // その後、最初の応答を受信してから、いくつかの追加パラメータを送付し、最後に、Connect パケットを送付する直前に呼び出される。 // Connect パケットの本体は文字列にして HTML5 クライアントに渡される。 // その後、HTML5 クライアントが WebSocket を ThinGate との間で確立した後に、 // HTML5 クライアントから最初のパケットとして Connect パケットの本体が渡されることになるのである。 string connectPacketData = await guaClient.StartAsync(cancel); webSocketUrl = await firstConnection.Socket.RequestSwitchToWebSocketAsync(cancel, Consts.ThinClient.RequestSwitchToWebSocketTimeoutMsecs); $"webSocketUrl = {webSocketUrl}"._Debug(); webSocketUrl._NotEmptyCheck(nameof(webSocketUrl)); // フル WebSocket URL を生成する var gateEndPoint = firstConnection.Socket.GatePhysicalEndPoint; // WebSocket URL を HTML クライアントに通知する var ready = new ThinClientAcceptReadyNotification { WebSocketFullUrl = "wss://" + IPUtil.GenerateWildCardDnsFqdn(gateEndPoint.Address, firstConnection.Socket.Options.ConnectParam.WebSocketWildCardDomainName, "ws-", "") + (gateEndPoint.Port == 443 ? "" : ":" + gateEndPoint.Port.ToString()) + webSocketUrl, SvcType = firstConnection.SvcType, ConnectPacketData = connectPacketData, WatermarkStr1 = firstConnection.WatermarkStr1, WatermarkStr2 = firstConnection.WatermarkStr2, Misc = firstConnection.Misc, Caps = firstConnection.Caps, IsStandaloneMode = firstConnection.Socket.Options.ConnectParam.IsStandaloneMode, }; if (firstConnection.Socket.Options.ConnectParam.WebSocketWildCardDomainName._IsSamei("<<!!samehost!!>>")) { ready.WebSocketFullUrl = webSocketUrl; } Dbg.Where(); await session.RequestAndWaitResponseAsync(ready, Consts.ThinClient.RequestHardTimeoutMsecs, Consts.ThinClient.RequestSoftTimeoutMsecs, isFinalAnswer : true); // 確立済みの firstConnection は何か 1 バイトでもデータを受信するか切断されるまで待機する // (このコネクションは ThinGate からみると用済みのため、新たなデータが届くことはないはずである) Dbg.Where("Waiting for unnecessary connection (already switched to WebSocket) disconnects."); // タイムアウトは 30 秒であります。 try { var data2 = await firstConnection.Stream._ReadAsyncWithTimeout(maxSize : 1024, timeout : 30 * 1000, cancel : cancel); } catch (Exception ex) { ex._Debug(); } Dbg.Where("Unnecessary connection (already switched to WebSocket) is disconnected."); } else { // Guacd Proxy Mode (デバッグ・開発用) await using var abort = new CancelWatcher(cancel); AsyncAutoResetEvent connectionAddedEvent = new AsyncAutoResetEvent(); AsyncAutoResetEvent connectedEvent = new AsyncAutoResetEvent(); Task? connectionKeepTask = null; NetTcpListener?listener = null; // このコネクションをキューに追加する ConcurrentQueue <ThinClientConnection> connectionQueue = new ConcurrentQueue <ThinClientConnection>(); try { connectionQueue.Enqueue(firstConnection); // コネクションのキューの長さが ConnectionQueueLength 未満になると自動的にコネクションを張る非同期タスクを開始する connectionKeepTask = TaskUtil.StartAsyncTaskAsync(async() => { int numRetry = 0; while (abort.IsCancellationRequested == false) { // キューの長さが少なくなれば追加コネクションを接続する while (abort.IsCancellationRequested == false) { if (connectionQueue.Count < Consts.ThinClient.ConnectionQueueLength) { session.Debug($"connectionQueue.Count ({connectionQueue.Count}) < Consts.ThinClient.ConnectionQueueLength ({Consts.ThinClient.ConnectionQueueLength})"); try { // 追加接続 ThinClientConnection additionalConnection = await DcConnectEx(wt, connectOptions, abort, false, false, async(req, c) => { // 認証コールバック await Task.CompletedTask; // キャッシュされた認証情報をそのまま応答 return(authResponseCache); }, async(req, c) => { // OTP コールバック await Task.CompletedTask; // OTP チケットを応答 return(new ThinClientOtpResponse { Otp = firstConnection.OtpTicket }); }, async(req, c) => { // 検疫・MAC コールバック await Task.CompletedTask; // チケットを応答 return(new ThinClientInspectResponse { Ticket = firstConnection.InspectTicket }); }); // 接続に成功したのでキューに追加 connectionQueue.Enqueue(additionalConnection); session.Debug($"Additional WideTunnel Connected. connectionQueue.Count = ({connectionQueue.Count})"); connectionAddedEvent.Set(true); numRetry = 0; } catch (Exception ex) { // 接続に失敗したので一定時間待ってリトライする ex._Debug(); session.Error(ex._GetObjectDump()); numRetry++; int waitTime = Util.GenRandIntervalWithRetry(Consts.ThinClient.ReconnectRetrySpanMsecs, numRetry, Consts.ThinClient.ReconnectRetrySpanMaxMsecs); if (waitTime == 0) { waitTime = 1; } session.Debug($"Additional tunnel establish failed. numRetry = {numRetry}. Wait for {waitTime} msecs..."); await connectedEvent.WaitOneAsync(waitTime, abort); } } else { break; } } if (abort.IsCancellationRequested) { break; } await connectedEvent.WaitOneAsync(1000, abort); } }); // Listen ソケットの開始 listener = LocalNet.CreateTcpListener(new TcpListenParam(isRandomPortMode: EnsureSpecial.Yes, async(listen, sock) => { session.Debug($"Listener ({sock.EndPointInfo._GetObjectDump()}) Accepted."); ThinClientConnection?connection = null; long giveupTick = TickNow + Consts.ThinClient.ConnectionQueueWaitTimeout; // キューにコネクションが貯まるまで待機する while (connectionQueue.TryDequeue(out connection) == false) { if (TickNow >= giveupTick) { session.Debug($"Listener ({sock.EndPointInfo._GetObjectDump()}): TickNow ({TickNow}) >= giveupTick ({giveupTick})"); return; } abort.ThrowIfCancellationRequested(); await connectionAddedEvent.WaitOneAsync(100, abort.CancelToken); } await using ThinClientConnection connection2 = connection; session.Debug($"Listener ({sock.EndPointInfo._GetObjectDump()}) Starting Relay Operation."); // 'A' を送信 byte[] a = new byte[] { (byte)'A' }; await connection.Stream.SendAsync(a, abort); var sockStream = sock.GetStream(true); RefLong totalBytes = new RefLong(); try { await Util.RelayDuplexStreamAsync(sockStream, connection.Stream, abort, totalBytes: totalBytes); } catch (Exception ex) { session.Debug($"Listener ({sock.EndPointInfo._GetObjectDump()}) RelayDuplexStreamAsync Exception = {ex._GetObjectDump()}"); } session.Debug($"Listener ({sock.EndPointInfo._GetObjectDump()}) Finished Relay Operation. Total Bytes = {totalBytes.Value}"); // RDP の場合はダミーデータを最後に流す if (connection.SvcType == ThinSvcType.Rdp) { byte[] dummySize = new byte[4096]; await sockStream.SendAsync(dummySize, abort); await Task.Delay(50, abort); } }, family: Options.ListenAddressFamily, address: Options.ListenAddress)); session.Debug($"Create Listener. Assigned Random Port = {listener.AssignedRandomPort}"); // 接続が完了いたしました var ready = new ThinClientAcceptReadyNotification { ListenEndPoint = new IPEndPoint(listener.AssignedRandomPort !.IPAddress, listener.AssignedRandomPort.Port), FirstConnection = firstConnection, Caps = firstConnection.Caps, }; Dbg.Where(); await session.RequestAndWaitResponseAsync(ready, Consts.ThinClient.RequestHardTimeoutMsecs, Consts.ThinClient.RequestSoftTimeoutMsecs, abort, isFinalAnswer : true); // コネクション数が 0 の状態が 30 秒以上継続した場合は終了します long connectionZeroStartTick = 0; while (true) { abort.ThrowIfCancellationRequested(); long now = TickNow; //$"listener.CurrentConnections = {listener.CurrentConnections}"._Debug(); if (listener.CurrentConnections == 0) { if (connectionZeroStartTick == 0) { connectionZeroStartTick = now; } } else { connectionZeroStartTick = 0; } if (connectionZeroStartTick != 0 && now >= (connectionZeroStartTick + Consts.ThinClient.ConnectionZeroTimeout)) { session.Debug($"All client connections disconnected. No more connection exists. connectionZeroStartTick = {connectionZeroStartTick}, now = {now}"); throw new CoresException("All client connections disconnected. No more connection exists."); } await abort.CancelToken._WaitUntilCanceledAsync(1000); } } catch (Exception ex) { session.Error(ex); throw; } finally { abort.Cancel(); await connectionKeepTask._TryAwait(noDebugMessage : true); await listener._DisposeSafeAsync(); foreach (var connection in connectionQueue) { await connection._DisposeSafeAsync(); } Dbg.Where(); } } }
protected override async Task GetValueAsync(SortedDictionary <string, string> ret, RefInt nextPollingInterval, CancellationToken cancel = default) { SnmpWorkSettings settings = Host.Settings; if (settings.PingTargets._IsSamei("none") || settings.PingTargets._IsSamei("null")) { return; } string hopsStr = "Hops"; if (settings.HopsToTTL) { hopsStr = "TTL"; } string[] pingTargets = settings.PingTargets._Split(StringSplitOptions.RemoveEmptyEntries, ","); numPerform++; foreach (string pingTarget in pingTargets) { cancel.ThrowIfCancellationRequested(); ParseTargetString(pingTarget, out string hostname, out string alias); bool ok = false; try { IPAddress ipAddress = await LocalNet.GetIpAsync(hostname, cancel : cancel); if (FirstPing.IsFirstCall()) { // JIT 対策 try { await LocalNet.SendPingAsync(ipAddress, pingCancel : cancel); } catch { } } int numTry = 3; if (numPerform >= 2) { // SpeedTest が動作中の場合は SpeedTest が完了するまで待機する await TaskUtil.AwaitWithPollAsync(Timeout.Infinite, 10, () => !SpeedTestClient.IsInProgress, cancel); // 試行回数を指定する numTry = Math.Min(Math.Max(settings.PingNumTry, 1), 100); } SendPingReply reply = await LocalNet.SendPingAndGetBestResultAsync(ipAddress, pingCancel : cancel, numTry : numTry); if (reply.Ok) { double rtt = reply.RttDouble; rtt = Math.Min(rtt, 2.0); int ttl = reply.Ttl; bool ttl_ok = false; if (ttl == 0) { // Use ping command to get TTL try { var result = await EasyExec.ExecAsync(ipAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6?Consts.LinuxCommands.Ping6 : Consts.LinuxCommands.Ping, $"-W 1 -c 1 {ipAddress.ToString()}", cancel : cancel, throwOnErrorExitCode : false); string[] lines = result.OutputStr._GetLines(true); foreach (string line in lines) { OneLineParams param = new OneLineParams(line, ' ', false); string ttlStr = param._GetStrFirst("ttl"); if (ttlStr._IsFilled()) { ttl = ttlStr._ToInt(); ttl_ok = true; break; } } } catch (Exception ex) { ex._Debug(); } } else { ttl_ok = true; } ret.TryAdd($"Time - {alias}", (rtt * 1000.0).ToString("F3")); if (ttl > 128) { ttl -= 128; } else if (ttl > 64) { ttl -= 64; } int hops = 64 - ttl; if (ttl_ok == false) { hops = 0; } hops._SetMax(0); hops._SetMin(64); ret.TryAdd($"{hopsStr} - {alias}", hops.ToString()); ok = true; } } catch (Exception ex) { ex._Debug(); } if (ok == false) { ret.TryAdd($"Time - {alias}", ""); ret.TryAdd($"{hopsStr} - {alias}", "0"); } } }
public RetryObserver() { _retryFault = TaskUtil.GetTask <RetryContext>(); _retryComplete = TaskUtil.GetTask <RetryContext>(); _postFault = TaskUtil.GetTask(); }
public FaultyConsumer() { _received = TaskUtil.GetTask <ConsumeContext <SimpleMessageInterface> >(); _consumerCreated.TrySetResult(this); }
public void Execute() { TaskUtil.Await(ExecuteAsync); }
internal void Connect() { if (this.state.CompareAndSet(ConnectionState.INITIAL, ConnectionState.CONNECTING)) { Address addr = UriUtil.ToAddress(connInfo.remoteHost, connInfo.username, connInfo.password ?? string.Empty); Tracer.InfoFormat("Creating Address: {0}", addr.Host); if (this.clientIdCanSet.CompareAndSet(true, false)) { if (this.ClientId == null) { connInfo.ResourceId = this.clientIdGenerator.GenerateId(); } else { connInfo.ResourceId = new Id(ClientId); } Tracer.InfoFormat("Staring Connection with Client Id : {0}", this.ClientId); } Open openFrame = CreateOpenFrame(this.connInfo); Task <Amqp.Connection> fconn = this.implCreate(addr, openFrame, this.OpenResponse); // wait until the Open request is sent this.impl = TaskUtil.Wait(fconn, connInfo.connectTimeout); if (fconn.Exception != null) { // exceptions thrown from TaskUtil are typically System.AggregateException and are usually transport exceptions for secure transport. // extract the innerException of interest and wrap it as an NMS exception if (fconn.Exception is AggregateException) { throw ExceptionSupport.Wrap(fconn.Exception.InnerException, "Failed to connect host {0}. Cause: {1}", openFrame.HostName, fconn.Exception.InnerException?.Message ?? fconn.Exception.Message); } else { throw ExceptionSupport.Wrap(fconn.Exception, "Failed to connect host {0}. Cause: {1}", openFrame.HostName, fconn.Exception?.Message); } } this.impl.Closed += OnInternalClosed; this.impl.AddClosedCallback(OnInternalClosed); this.latch = new CountDownLatch(1); ConnectionState finishedState = ConnectionState.UNKNOWN; // Wait for Open response try { bool received = this.latch.await((this.Info.requestTimeout == 0) ? Timeout.InfiniteTimeSpan : this.RequestTimeout); if (received && this.impl.Error == null && fconn.Exception == null) { Tracer.InfoFormat("Connection {0} has connected.", this.impl.ToString()); finishedState = ConnectionState.CONNECTED; // register connection factory once client Id accepted. MessageFactory <ConnectionInfo> .Register(this); } else { if (!received) { // Timeout occured waiting on response Tracer.InfoFormat("Connection Response Timeout. Failed to receive response from {0} in {1}ms", addr.Host, this.Info.requestTimeout); } finishedState = ConnectionState.INITIAL; if (fconn.Exception == null) { if (!received) { throw ExceptionSupport.GetTimeoutException(this.impl, "Connection {0} has failed to connect in {1}ms.", ClientId, connInfo.closeTimeout); } Tracer.ErrorFormat("Connection {0} has Failed to connect. Message: {1}", ClientId, (this.impl.Error == null ? "Unknown" : this.impl.Error.ToString())); throw ExceptionSupport.GetException(this.impl, "Connection {0} has failed to connect.", ClientId); } else { throw ExceptionSupport.Wrap(fconn.Exception, "Connection {0} failed to connect.", ClientId); } } } finally { this.latch = null; this.state.GetAndSet(finishedState); if (finishedState != ConnectionState.CONNECTED) { this.impl.Close(TimeSpan.FromMilliseconds(connInfo.closeTimeout), null); } } } }