Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Bo Jacobsen 593 posts 2389 karma points
    Feb 03, 2021 @ 11:06
    Bo Jacobsen
    0

    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?

Please Sign in or register to post replies

Write your reply to:

Draft