async void connectButton_Click(object sender, EventArgs e)
 {
     connectButton.Enabled = false;
     var options = new WorkerOptions { Tubes = { watchTextBox.Text.Trim() } };
     subscription = await BeanstalkConnection.ConnectWorkerAsync(_connectionString, options, async (conn, job) =>
     {
         jobs.Add(job);
         await conn.DeleteAsync();
         await Task.Delay(1000);
     });
     disconnectButton.Enabled = true;
 }
Example #2
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 #3
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 #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
        /// <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);
        }