ScheduleTask using scopeProvider CreateScope with autoComplete throw connection error from time to time
HI all.
We are getting 3 errors when using a custom IComponent running a BackgroundTaskRunner with a task inherited by RecurringTaskBase and a custom email service, that i dunno how to work around.
IComponent
public class ScheduleTaskCompontent : IComponent
{
private readonly ILogger _logger;
private readonly IEmailTaskService _emailTaskService;
private BackgroundTaskRunner<IBackgroundTask> _tasksRunner;
public ScheduleTaskCompontent(ILogger logger, IEmailTaskService emailTaskService)
{
_logger = logger;
_emailTaskService = emailTaskService;
}
public void Initialize()
{
_tasksRunner = new BackgroundTaskRunner<IBackgroundTask>("ScheduleTasks", _logger);
var sendOutTask = new SendOutTask(_tasksRunner, 5000, 30000, _logger, _emailTaskService);
_tasksRunner.Add(sendOutTask);
}
public void Terminate()
{
}
}
RecurringTaskBase
public class SendOutTask : RecurringTaskBase
{
private readonly ILogger _logger;
private readonly IEmailTaskService _emailTaskService;
public override bool IsAsync => true;
public override bool RunsOnShutdown => false;
public SendOutTask(IBackgroundTaskRunner<RecurringTaskBase> runner, int delayMilliseconds, int periodMilliseconds, ILogger logger, IEmailTaskService emailTaskService) : base(runner, delayMilliseconds, periodMilliseconds)
{
_logger = logger;
_emailTaskService = emailTaskService;
}
public override Task<bool> PerformRunAsync(CancellationToken token)
{
try
{
_emailTaskService.SendEmails(4);
_logger.Info<SendOutTask>("ScheduleTask[SendOut] OK!");
}
catch (Exception ex)
{
_logger.Error<SendOutTask>(ex, "ScheduleTask[SendOut] ERROR!");
}
return Task.FromResult<bool>(true);
}
}
IEmailTaskService
public class EmailTaskService : IEmailTaskService
{
private readonly IScopeProvider _scopeProvider;
private readonly ILogger _logger;
private readonly IHostingEnvironmentService _hostingEnvironmentService;
private readonly IFileService _fileService;
public EmailTaskService(IScopeProvider scopeProvider, ILogger logger, IHostingEnvironmentService hostingEnvironmentService, IFileService fileService)
{
_scopeProvider = scopeProvider;
_logger = logger;
_hostingEnvironmentService = hostingEnvironmentService;
_fileService = fileService;
}
public void SendEmails(int take = 30)
{
using (var scope = _scopeProvider.CreateScope(autoComplete: true))
{
var sql = Sql.Builder.Select("*").From(TableInfo.FromPoco(typeof(EmailTask)).TableName).Where("bounces < 4").OrderBy("id");
var allMails = scope.Database.Fetch<EmailTask>(sql);
if (allMails != null && allMails.Any())
{
using (var client = new SmtpClient())
{
foreach (var mail in allMails.Take(take))
{
var isSuccess = false;
try
{
using (var mailMessage = new MailMessage()
{
IsBodyHtml = true,
BodyEncoding = Encoding.UTF8,
HeadersEncoding = Encoding.UTF8,
SubjectEncoding = Encoding.UTF8,
Priority = MailPriority.High,
BodyTransferEncoding = System.Net.Mime.TransferEncoding.Base64,
Subject = mail.Subject,
Body = mail.Body,
From = new MailAddress(mail.SenderEmail, !string.IsNullOrEmpty(mail.SenderName) ? mail.SenderName : mail.SenderEmail, Encoding.UTF8)
})
{
mailMessage.To.Add(mail.ReceiverEmails);
if (!string.IsNullOrEmpty(mail.Bcc))
{
mailMessage.Bcc.Add(mail.Bcc);
}
if (!string.IsNullOrEmpty(mail.Cc))
{
mailMessage.CC.Add(mail.Cc);
}
if (!string.IsNullOrEmpty(mail.Files))
{
var files = mail.Files.Split(',');
foreach (var file in files)
{
mailMessage.Attachments.Add(new Attachment(_hostingEnvironmentService.MapPath(file.Trim())));
}
}
client.Send(mailMessage);
isSuccess = true;
}
}
catch (Exception ex)
{
mail.SentDate = DateTime.Now;
mail.Bounces = mail.Bounces + 1;
mail.ErrorMessage = ex.Message;
isSuccess = false;
}
if (isSuccess)
{
var mailId = mail.Id;
scope.Database.Delete<EmailTask>(mail);
_fileService.DeleteFromEmails(mailId.ToString());
}
else
{
scope.Database.Update(mail);
}
}
}
}
}
}
}
The first error is:
System.Data.SqlClient.SqlException (0x80131904): Execution Timeout Expired. The timeout period elapsed prior to completion of the operation or the server is not responding. ---> System.ComponentModel.Win32Exception (0x80004005): The wait operation timed out
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj, UInt32 error)
at System.Data.SqlClient.TdsParserStateObject.ReadSniSyncOverAsync()
at System.Data.SqlClient.TdsParserStateObject.TryReadNetworkPacket()
at System.Data.SqlClient.TdsParserStateObject.TryPrepareBuffer()
at System.Data.SqlClient.TdsParserStateObject.TryReadByte(Byte& value)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
at System.Data.SqlClient.TdsParser.TdsExecuteTransactionManagerRequest(Byte[] buffer, TransactionManagerRequestType request, String transactionName, TransactionManagerIsolationLevel isoLevel, Int32 timeout, SqlInternalTransaction transaction, TdsParserStateObject stateObj, Boolean isDelegateControlRequest)
at System.Data.SqlClient.SqlInternalConnectionTds.ExecuteTransactionYukon(TransactionRequest transactionRequest, String transactionName, IsolationLevel iso, SqlInternalTransaction internalTransaction, Boolean isDelegateControlRequest)
at System.Data.SqlClient.SqlInternalConnectionTds.ExecuteTransaction(TransactionRequest transactionRequest, String name, IsolationLevel iso, SqlInternalTransaction internalTransaction, Boolean isDelegateControlRequest)
at System.Data.SqlClient.SqlInternalConnection.BeginSqlTransaction(IsolationLevel iso, String transactionName, Boolean shouldReconnect)
at System.Data.SqlClient.SqlConnection.BeginTransaction(IsolationLevel iso, String transactionName)
at System.Data.SqlClient.SqlConnection.BeginDbTransaction(IsolationLevel isolationLevel)
at System.Data.Common.DbConnection.BeginTransaction(IsolationLevel isolationLevel)
at StackExchange.Profiling.Data.ProfiledDbConnection.BeginDbTransaction(IsolationLevel isolationLevel) in C:\projects\dotnet\src\MiniProfiler.Shared\Data\ProfiledDbConnection.cs:line 138
at System.Data.Common.DbConnection.BeginTransaction(IsolationLevel isolationLevel)
at Umbraco.Core.Persistence.FaultHandling.RetryDbConnection.BeginDbTransaction(IsolationLevel isolationLevel) in D:\a\1\s\src\Umbraco.Core\Persistence\FaultHandling\RetryDbConnection.cs:line 30
at System.Data.Common.DbConnection.BeginTransaction(IsolationLevel isolationLevel)
at NPoco.Database.BeginTransaction(IsolationLevel isolationLevel)
at Umbraco.Core.Scoping.Scope.get_Database() in D:\a\1\s\src\Umbraco.Core\Scoping\Scope.cs:line 242
at XXX.Core.Services.EmailTaskService.SendEmails(Int32 take) in ...\XXX.Core\Services\EmailTaskService.cs:line 78
at XXX.Core.RecurringTasks.SendOutTask.PerformRunAsync(CancellationToken token) in ...\XXX.Core\RecurringTasks\SendOutTask.cs:line 29
ClientConnectionId:3017f3e2-98c7-4fdd-a972-b938ba61b933
Error Number:-2,State:0,Class:11
The second error is:
System.InvalidOperationException: Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.
at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
at System.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
at System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource`1 retry)
at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)
at System.Data.SqlClient.SqlConnection.Open()
at NPoco.Database.OpenSharedConnectionImp(Boolean isInternal)
at NPoco.Database.BeginTransaction(IsolationLevel isolationLevel)
at Umbraco.Core.Scoping.Scope.get_Database() in D:\a\1\s\src\Umbraco.Core\Scoping\Scope.cs:line 242
at Umbraco.Core.Scoping.Scope.WriteLock(Int32[] lockIds) in D:\a\1\s\src\Umbraco.Core\Scoping\Scope.cs:line 492
at Umbraco.Core.Services.Implement.ServerRegistrationService.TouchServer(String serverAddress, String serverIdentity, TimeSpan staleTimeout) in D:\a\1\s\src\Umbraco.Core\Services\Implement\ServerRegistrationService.cs:line 50
at Umbraco.Web.Compose.DatabaseServerRegistrarAndMessengerComponent.TouchServerTask.PerformRun() in D:\a\1\s\src\Umbraco.Web\Compose\DatabaseServerRegistrarAndMessengerComponent.cs:line 259
The third error is:
Failed (will repeat). from Umbraco.Web.Compose.DatabaseServerRegistrarAndMessengerComponent+InstructionProcessTask
Most of the time the task works, but sometimes we get these errors.
Do anyone have a clue?
Should i close the scope earlier or send the work to other threads?
ScheduleTask using scopeProvider CreateScope with autoComplete throw connection error from time to time
HI all.
We are getting 3 errors when using a custom IComponent running a BackgroundTaskRunner with a task inherited by RecurringTaskBase and a custom email service, that i dunno how to work around.
IComponent
RecurringTaskBase
IEmailTaskService
The first error is:
The second error is:
The third error is:
Most of the time the task works, but sometimes we get these errors.
Do anyone have a clue?
Should i close the scope earlier or send the work to other threads?
is working on a reply...