Example #1
0
        /// <summary>
        /// Schedules a worker with a dedicated TCP connection to repeatedly reserve jobs
        /// from the specified tubes and process them.
        /// </summary>
        /// <param name="configuration">The configuration for the Beanstalk connection.</param>
        /// <param name="options">The worker options.</param>
        /// <param name="worker">The delegate used to processed reserved jobs.</param>
        /// <returns>A token which stops the worker when disposed.</returns>
        public static Task <IDisposable> ConnectWorkerAsync <T>(ConnectionConfiguration configuration, WorkerOptions options, Func <IWorker, Job <T>, Task> worker)
        {
            WorkerFunc workerFunc = (w, untypedJob) =>
            {
                // If the deserializer throws, this will be handled like any other failure of the WorkerFunc.
                var obj      = configuration.JobSerializer.Deserialize <T>(untypedJob.Data);
                var typedJob = new Job <T>(untypedJob.Id, untypedJob.Data, obj);
                return(worker(w, typedJob));
            };

            return(ConnectWorkerAsync(configuration, options, workerFunc));
        }
Example #2
0
        /// <summary>Creates a progress form starting a background thread immediately</summary>
        public ProgressForm(string title, string desc, Icon icon, ProgressBarStyle style, WorkerFunc func, object arg = null, ThreadPriority priority = ThreadPriority.Normal)
            : this(title, desc, icon, style)
        {
            m_allow_cancel = true;
            Done           = new ManualResetEvent(false);
            CancelSignal   = new ManualResetEvent(false);
            func           = func ?? ((f, o, p) =>
            {
                // Default worker function, just waits till Cancel is signalled
                for (; !CancelPending; Thread.Sleep(100))
                {
                    p(new UserState {
                    });
                }
            });

            // Start the task
            var dispatcher = Dispatcher.CurrentDispatcher;

            m_thread = new Thread(new ThreadStart(() =>
            {
                try
                {
                    func(this, arg, us => dispatcher.BeginInvoke(new Progress(UpdateProgress), us.Clone()));
                    dispatcher.BeginInvoke(new Progress(UpdateProgress), new UserState {
                        FractionComplete = 1.0
                    });
                }
                catch (OperationCanceledException)
                {
                    CancelSignal.Set();
                }
                catch (AggregateException ex)
                {
                    m_error = ex.InnerExceptions.FirstOrDefault(e => !(e is OperationCanceledException));
                    if (m_error == null)
                    {
                        CancelSignal.Set();
                    }
                }
                catch (Exception ex)
                {
                    m_error = ex;
                }
                Done.Set();
                dispatcher.BeginInvoke(new Progress(UpdateProgress), new UserState {
                    CloseDialog = true
                });
            }))
            {
                Name         = "ProgressForm",
                Priority     = priority,
                IsBackground = true,
            };
            m_thread.Start();
        }
Example #3
0
        public ProgressUI(Window?owner, string title, string desc, ImageSource?image, CancellationToken cancel, WorkerFunc worker, object?arg = null, ThreadPriority priority = ThreadPriority.Normal)
            : this(owner, title, desc, image, cancel)
        {
            try
            {
                worker ??= DefaultWorkerFunc;
                void DefaultWorkerFunc(ProgressUI ui, object?a, ProgressCB p)
                {
                    // Default worker function just waits till cancel is signalled
                    for (; !CancelPending; Thread.Sleep(100))
                    {
                        p(new UserState {
                        });
                    }
                }

                // Start the worker task
                m_thread = new Thread(new ThreadStart(ThreadEntry))
                {
                    Name         = "ProgressUI",
                    Priority     = priority,
                    IsBackground = true,
                };
                void ThreadEntry()
                {
                    var progress_cb = new ProgressCB(UpdateProgress);

                    try
                    {
                        // Run the worker task
                        worker(this, arg, us => Dispatcher.BeginInvoke(progress_cb, us));
                        Dispatcher.BeginInvoke(progress_cb, new UserState {
                            FractionComplete = 1f
                        });
                    }
                    catch (Exception ex)
                    {
                        if (ex is OperationCanceledException)
                        {
                            m_cancel.Cancel();
                        }
                        else
                        {
                            Error = ex;
                        }
                    }

                    // Set the event to say "task done"
                    Done.Set();
                    Dispatcher.BeginInvoke(progress_cb, new UserState {
                        CloseDialog = true
                    });
                }
                m_thread.Start();
            }
            catch
            {
                Dispose();
                throw;
            }
        }
Example #4
0
 /// <summary>
 /// Schedules a worker with a dedicated TCP connection to repeatedly reserve jobs
 /// from the specified tubes and process them.
 /// </summary>
 /// <param name="connectionString">The connection string.</param>
 /// <param name="options">The worker options.</param>
 /// <param name="worker">The delegate used to processed reserved jobs.</param>
 /// <returns>A token which stops the worker when disposed.</returns>
 public static Task <IDisposable> ConnectWorkerAsync(string connectionString, WorkerOptions options, WorkerFunc worker)
 {
     return(ConnectWorkerAsync(ConnectionConfiguration.Parse(connectionString), options, worker));
 }
Example #5
0
        async Task WorkerLoop(WorkerFunc workerFunc, WorkerOptions options, CancellationToken cancellationToken)
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                var job = await ReserveAsync(cancellationToken).ConfigureAwait(false);

                if (job == null)
                {
                    continue; // DEADLINE_SOON
                }
                try
                {
                    var worker = new Worker(job, this);

                    // Details: http://blog.stephencleary.com/2013/08/startnew-is-dangerous.html
                    await Task.Factory.StartNew(
                        () => workerFunc(worker, job),
                        cancellationToken,
                        TaskCreationOptions.DenyChildAttach,
                        options.TaskScheduler)
                    .Unwrap()
                    .ConfigureAwait(false);

                    if (worker.Completed)
                    {
                        continue;
                    }

                    // else, fall through to the failure handling
                }
                catch (Exception)
                {
                    // Carry on outside the catch...
                }

                // Failure handling
                // Either the workerFunc threw or didn't delete/release/bury the job
                var cons = this as IConsumer;
                int priority;
                switch (options.FailureBehavior)
                {
                case WorkerFailureBehavior.Bury:
                    priority = options.FailurePriority ?? (await cons.JobStatisticsAsync(job.Id).ConfigureAwait(false)).Priority;
                    await cons.BuryAsync(job.Id, priority).ConfigureAwait(false);

                    continue;

                case WorkerFailureBehavior.Release:
                    priority = options.FailurePriority ?? (await cons.JobStatisticsAsync(job.Id).ConfigureAwait(false)).Priority;
                    await cons.ReleaseAsync(job.Id, priority, options.FailureReleaseDelay).ConfigureAwait(false);

                    continue;

                case WorkerFailureBehavior.Delete:
                    await cons.DeleteAsync(job.Id).ConfigureAwait(false);

                    continue;

                case WorkerFailureBehavior.NoAction:
                    continue;

                default:
                    throw new InvalidOperationException("Unhandled WorkerFailureBehavior '" + options.FailureBehavior.ToString() + "'");
                }
            }
        }
Example #6
0
        /// <summary>
        /// Schedules a worker with a dedicated TCP connection to repeatedly reserve jobs
        /// from the specified tubes and process them.
        /// </summary>
        /// <param name="configuration">The configuration for the Beanstalk connection.</param>
        /// <param name="options">The worker options.</param>
        /// <param name="worker">The delegate used to processed reserved jobs.</param>
        /// <returns>A token which stops the worker when disposed.</returns>
        public static async Task <IDisposable> ConnectWorkerAsync(ConnectionConfiguration configuration, WorkerOptions options, WorkerFunc worker)
        {
            // Must capture the context before the first await
            if (options.TaskScheduler == null)
            {
                options.TaskScheduler = SynchronizationContext.Current == null
                    ? TaskScheduler.Default
                    : TaskScheduler.FromCurrentSynchronizationContext();
            }

            var conn = await BeanstalkConnection.ConnectAsync(configuration).ConfigureAwait(false);

            try
            {
                // Just take the default tube if none was given
                if (options.Tubes.Count > 0)
                {
                    foreach (var tube in options.Tubes)
                    {
                        await((IConsumer)conn).WatchAsync(tube).ConfigureAwait(false);
                    }
                    if (!options.Tubes.Contains("default"))
                    {
                        await((IConsumer)conn).IgnoreAsync("default").ConfigureAwait(false);
                    }
                }
            }
            catch
            {
                conn.Dispose();
                throw;
            }

            var cts        = new CancellationTokenSource();
            var disposable = Disposable.Create(() =>
            {
                cts.Cancel();
                cts.Dispose();
                conn.Dispose();
            });

#pragma warning disable 4014
            Task[] workerLoops = new Task[options.NumberOfWorkers];
            for (var i = 0; i < options.NumberOfWorkers; i++)
            {
                workerLoops[i] = conn.WorkerLoop(worker, options, cts.Token);
            }

            // Ensure we handle any thrown exceptions
            Task.WhenAll(workerLoops).ContinueWith(t =>
            {
                disposable.Dispose();
                if (t.Exception != null)
                {
                    t.Exception.Handle(ex => true);
                }
            }, TaskContinuationOptions.OnlyOnFaulted);
#pragma warning restore 4014

            return(disposable);
        }