public static async Task <CrawlResults> RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log) { var request = context.GetInput <CrawlRequest>(); var state = new CrawlState(configuration: request); state.AddUrl($"{request.Host}/sitemap.xml"); var currentDepth = 0; while (state.HasAwaiting && currentDepth < MAX_CRAWL_DEPTH) { var urlsToCrawl = state.Awaiting(); var crawlTasks = urlsToCrawl .Select(x => new CrawlUrlRequest { Host = request.Host, Url = x }) .Select(x => context.CallActivityAsync <UrlInfo>("CrawlUrl", x)) .ToList(); await Task.WhenAll(crawlTasks.ToArray()); var result = crawlTasks.Select(x => x.Result).ToList(); state.UpdateWithResults(result); currentDepth++; } return(new CrawlResults(request.Host, state)); }
private Transformer(CxRestContext ctx, CancellationToken token, String previousStatePath, IProjectFilter filter) { RestContext = ctx; CancelToken = token; Filter = filter; _state = new CrawlState(previousStatePath); ResolveScans().Wait(); }
/// <summary> /// Creates a crawling spider with an undefined data origin. /// </summary> public Spider() { this.state = CrawlState.Stopped; this.lastUpdated = DateTime.MinValue; }
/// <summary> /// An event handler called when the spider starts crawling. /// </summary> protected void OnStarted() { lock (this.sync) { // If the spider is in the running state, throw an exception. if (this.state != CrawlState.Stopped) throw new SpiderException("Cannot begin spider crawling because the spider is not in the stopped state."); // Change the spider state to running. this.state = CrawlState.Running; // Raise the events. if (this.StateChanged != null) this.StateChanged(this, new SpiderEventArgs(this)); if (this.CrawlStarted != null) this.CrawlStarted(this, new SpiderEventArgs(this)); } }
/// <summary> /// An event handler called when the spider finishes crawling. /// </summary> protected void OnFinished() { lock (this.sync) { // If the spider is not in the running state, throw an exception. if (this.state == CrawlState.Stopped) throw new SpiderException("Cannot finish spider crawling because the spider is already in the stopped state."); // Change the spider state to running. this.state = CrawlState.Stopped; // Raise the event. if (this.StateChanged != null) this.StateChanged(this, new SpiderEventArgs(this)); if (this.CrawlFinished != null) this.CrawlFinished(this, new SpiderEventArgs(this)); } }
/// <summary> /// An event handler called when the user cancels the spider crawling. /// </summary> protected void OnCanceled() { lock (this.sync) { // If the spider is not in the running state, throw an exception. if (this.state != CrawlState.Running) throw new SpiderException("Cannot cancel spider crawling because the spider is not in the running state."); // Change the spider state to canceling. this.state = CrawlState.Canceling; // Raise the event. if (this.StateChanged != null) this.StateChanged(this, new SpiderEventArgs(this)); } }
/// <summary> /// 常駐クロール処理を開始する(処理は別スレッドで非同期に進行) /// </summary> public virtual void StartAlwaysCrawl() { if (AlwaysCrawlIsRunning) { throw new InvalidOperationException("すでに常駐クロール処理が実行中です。"); } if (ManualCrawlIsRunning) { throw new InvalidOperationException("手動クロールと常駐クロールを同時に実行しようとしました。"); } // キャンセル用のオブジェクトを生成 var ctSource = new CancellationTokenSource(); var res = new Result() { Finished = false }; // 常駐クロールのメイン処理 (別スレッドで実行) var t = Task.Factory.StartNew(() => { Logger.Info("常駐クロール開始"); // 開始を報告 ((IProgress <ProgressState>)AlwaysCrawlProgress).Report(new ProgressState() { CurrentStep = ProgressState.Step.AlwaysCrawlBegin }); // ファイル監視オブジェクトを生成 var watchers = new List <System.IO.FileSystemWatcher>(); // ワークスタックを初期化 var workStack = new Stack <IWork>(); var workStackSet = new HashSet <IWork>(); // 処理の重複を確認するためのセット // 最初にフルクロールを実行 workStack.Push(new Work.ManualCrawl(App, isBackgroundCrawl: true)); // ファイル監視オブジェクト生成 var fileWatcher = new FileWatcher(Logger, App.UserSettings.TargetFolders.Select(f => f.Path).OrderBy(p => p).ToList()); // メイン処理 try { // 監視スタート fileWatcher.Start(); // 無視設定を取得 var ignoreSettings = App.GetIgnoreSettings(); while (true) { // ファイル変更イベントがあれば、対応するワークを生成 if (fileWatcher.EventQueue.Count >= 1) { while (fileWatcher.EventQueue.Count >= 1) { // キューの先頭にあるイベントを取得 var evt = fileWatcher.EventQueue[0]; fileWatcher.EventQueue.RemoveAt(0); if (Logger.IsTraceEnabled) { Logger.Trace("FileSystemEvent: {0} {1} {2}", evt.Type, evt.TargetType, evt.Path); } // イベントの種類に応じたワークを生成 IWork work = null; if (evt.Type == FileSystemEventType.UPDATE) { if (evt.TargetType == FileSystemEventTargetType.FILE) { work = new Work.BackgroundFileCrawl(App, evt.Path, ignoreSettings); } else if (evt.TargetType == FileSystemEventTargetType.FOLDER) { work = new Work.BackgroundDirectoryCrawl(App, evt.Path, ignoreSettings); } } else if (evt.Type == FileSystemEventType.DELETE) { if (evt.TargetType == FileSystemEventTargetType.FILE) { work = new Work.DBDocumentDelete(App, true, evt.Path); } else if (evt.TargetType == FileSystemEventTargetType.FOLDER) { work = new Work.DBDirectoryDelete(App, true, evt.Path); } } // 処理対象外イベントならスキップ if (work == null) { continue; } // スタックに登録 workStack.Push(work); workStackSet.Add(work); if (Logger.IsTraceEnabled) { Logger.Trace("Work Push: {0}", work.TraceLogCaption); Logger.Trace("Work Stack ({0}): [{1}]", workStack.Count, string.Join(", ", workStack.Select(w => w.TraceLogCaption))); } } } // ワークキューにワークがあれば、1つ取得して実行 if (workStack.Count >= 1) { var nextWork = workStack.Pop(); nextWork.Execute(workStack, res, ctSource.Token, AlwaysCrawlProgress); ctSource.Token.ThrowIfCancellationRequested(); // キャンセル受付 } else { // ワークが1つも無い状態であれば、進捗を報告した上で、5秒待つ (1秒ごとにキャンセル受け付け) ((IProgress <ProgressState>)AlwaysCrawlProgress).Report(new ProgressState() { CurrentStep = ProgressState.Step.Finish }); for (var i = 0; i < 5; i++) { Thread.Sleep(1000); ctSource.Token.ThrowIfCancellationRequested(); // キャンセル受付 } // ファイル監視オブジェクトを再起動 fileWatcher.Restart(); } } } catch (OperationCanceledException) { // ファイル監視オブジェクトをすべて解放 fileWatcher.Stop(); Logger.Info("常駐クロール終了"); // 終了を報告 ((IProgress <ProgressState>)AlwaysCrawlProgress).Report(new ProgressState() { CurrentStep = ProgressState.Step.AlwaysCrawlEnd }); return; } catch (Exception ex) { Logger.Error("常駐クロール処理でエラーが発生しました"); Logger.Error(ex.ToString()); } }, ctSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default); // 実行状態を設定 AlwaysCrawlState = new CrawlState(t, ctSource); }
/// <summary> /// 非同期に全体クロール処理の実行を開始する /// </summary> public virtual async Task <Result> RunFullCrawlAsync( IEnumerable <string> targetDirPaths , EventHandler <ProgressState> progressChangedCallback = null) { if (ManualCrawlIsRunning) { throw new InvalidOperationException("すでに手動クロール処理が実行中です。"); } if (AlwaysCrawlIsRunning) { throw new InvalidOperationException("手動クロールと常駐クロールを同時に実行しようとしました。"); } // 進捗報告用オブジェクトの作成 var progress = new Progress <ProgressState>(); if (progressChangedCallback != null) { progress.ProgressChanged += progressChangedCallback; } // 処理取り消しを可能とするためにCancellationTokenSourceを生成 var ctSource = new CancellationTokenSource(); // クロール結果オブジェクトを生成 var res = new Result() { Finished = false }; // 手動クロールのメイン処理(別スレッドで実行) var t = Task.Run(() => { Logger.Info("手動クロール開始"); try { // (1) 登録ファイル数の計測 (別スレッドで並列実行) // ※内部で例外が発生した場合には、ログのみ出力して処理を中断するため注意 Task.Run(() => { var workStack = new Stack <IWork>(); workStack.Push(new Work.TargetFileCount(App, isBackgroundCrawl: true, targetDirPaths: targetDirPaths)); // ワークスタックが空になるまで順次実行 while (workStack.Count >= 1) { var work = workStack.Pop(); work.Execute(workStack, res, ctSource.Token, progress); Thread.Sleep(0); // 他のスレッドに処理を渡す ctSource.Token.ThrowIfCancellationRequested(); // 取り消し判定 } }); // (2) メインクロール処理 { var workStack = new Stack <IWork>(); workStack.Push(new Work.ManualCrawl(App, isBackgroundCrawl: false, targetDirPaths: targetDirPaths)); // ワークスタックが空になるまで順次実行 while (workStack.Count >= 1) { var work = workStack.Pop(); work.Execute(workStack, res, ctSource.Token, progress); Thread.Sleep(0); // 他のスレッドに処理を渡す ctSource.Token.ThrowIfCancellationRequested(); // 取り消し判定 } } } catch (OperationCanceledException) { Logger.Info("手動クロールをキャンセル"); return; } Logger.Info("手動クロール完了"); // 手動クロール処理完了を通知 ((IProgress <ProgressState>)progress).Report(new ProgressState() { CurrentStep = ProgressState.Step.Finish }); res.Finished = true; }, ctSource.Token); // 実行状態を設定 ManualCrawlState = new CrawlState(t, ctSource); // タスク完了/キャンセルを待機 await t; // タスクが完了/キャンセル受付したら結果を戻す return(res); }