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 438 posts 1818 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?

  • This forum is in read-only mode while we transition to the new forum.

    You can continue this topic on the new forum by tapping the "Continue discussion" link below.

Please Sign in or register to post replies