public ClientConnectionSettings GetConnection(TaskId taskId)
 {
     lock (sync)
     {
         if (_connections.ContainsKey(taskId))
             return _connections[taskId];
         return null;
     }
 }
 public void SetConnection(TaskId taskId, ClientConnectionSettings connectionSettings)
 {
     lock (sync)
     {
         if (_connections.ContainsKey(taskId))
             _connections[taskId] = connectionSettings;
         else
             _connections.Add(taskId, connectionSettings);
     }
 }
 public void SetLastCleaned(TaskId taskId)
 {
     using (var connection = CreateNewConnection(taskId))
     {
         using (var command = new SqlCommand(TaskQueryBuilder.SetLastCleanUpTimeQuery, connection))
         {
             command.Parameters.Add(new SqlParameter("@ApplicationName", SqlDbType.VarChar, 200)).Value = taskId.ApplicationName;
             command.Parameters.Add(new SqlParameter("@TaskName", SqlDbType.VarChar, 200)).Value = taskId.TaskName;
             command.ExecuteNonQuery();
         }
     }
 }
        public IList<ProtoListBlockItem> GetListBlockItems(TaskId taskId, string listBlockId)
        {
            var results = new List<ProtoListBlockItem>();

            try
            {
                using (var connection = CreateNewConnection(taskId))
                {
                    var command = connection.CreateCommand();
                    command.CommandText = ListBlockQueryBuilder.GetListBlockItems;
                    command.CommandTimeout = ConnectionStore.Instance.GetConnection(taskId).QueryTimeoutSeconds;
                    command.Parameters.Add("@BlockId", SqlDbType.BigInt).Value = long.Parse(listBlockId);

                    using (var reader = command.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            var listBlock = new ProtoListBlockItem();
                            listBlock.ListBlockItemId = reader["ListBlockItemId"].ToString();
                            listBlock.Value = SerializedValueReader.ReadValueAsString(reader, "Value", "CompressedValue");
                            listBlock.Status = (ItemStatus)int.Parse(reader["Status"].ToString());

                            if (reader["LastUpdated"] == DBNull.Value)
                                listBlock.LastUpdated = DateTime.MinValue;
                            else
                                listBlock.LastUpdated = reader.GetDateTime(5);

                            if (reader["StatusReason"] == DBNull.Value)
                                listBlock.StatusReason = null;
                            else
                                listBlock.StatusReason = reader.GetString(6);

                            if (reader["Step"] == DBNull.Value)
                                listBlock.Step = null;
                            else
                                listBlock.Step = reader.GetByte(7);

                            results.Add(listBlock);
                        }
                    }
                }
            }
            catch (SqlException sqlEx)
            {
                if (TransientErrorDetector.IsTransient(sqlEx))
                    throw new TransientException("A transient exception has occurred", sqlEx);

                throw;
            }

            return results;
        }
        protected SqlConnection CreateNewConnection(TaskId taskId)
        {
            try
            {
                var connection = new SqlConnection(ConnectionStore.Instance.GetConnection(taskId).ConnectionString);
                connection.Open();

                return connection;
            }
            catch (SqlException sqlEx)
            {
                if (TransientErrorDetector.IsTransient(sqlEx))
                    throw new TransientException("A transient exception has occurred", sqlEx);

                throw;
            }
        }
        public DateTime GetLastTaskCleanUpTime(TaskId taskId)
        {
            using (var connection = CreateNewConnection(taskId))
            {
                using (var command = new SqlCommand(TaskQueryBuilder.GetLastCleanUpTimeQuery, connection))
                {
                    command.Parameters.Add(new SqlParameter("@ApplicationName", SqlDbType.VarChar, 200)).Value = taskId.ApplicationName;
                    command.Parameters.Add(new SqlParameter("@TaskName", SqlDbType.VarChar, 200)).Value = taskId.TaskName;
                    using (var reader = command.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            if (reader["LastCleaned"] == DBNull.Value)
                                return DateTime.MinValue;

                            return DateTime.Parse(reader["LastCleaned"].ToString());
                        }
                    }
                }
            }

            return DateTime.MinValue;
        }
        private CompleteCriticalSectionResponse ReturnCriticalSectionToken(TaskId taskId, int taskDefinitionId, string taskExecutionId, CriticalSectionType criticalSectionType)
        {
            var response = new CompleteCriticalSectionResponse();

            using (var connection = CreateNewConnection(taskId))
            {
                SqlTransaction transaction = connection.BeginTransaction(IsolationLevel.Serializable);

                var command = connection.CreateCommand();
                command.Transaction = transaction;

                if (criticalSectionType == CriticalSectionType.User)
                    command.CommandText = TokensQueryBuilder.ReturnUserCriticalSectionTokenQuery;
                else
                    command.CommandText = TokensQueryBuilder.ReturnClientCriticalSectionTokenQuery;

                command.CommandTimeout = ConnectionStore.Instance.GetConnection(taskId).QueryTimeoutSeconds;
                command.Parameters.Add("@TaskDefinitionId", SqlDbType.Int).Value = taskDefinitionId;
                command.Parameters.Add("@TaskExecutionId", SqlDbType.Int).Value = int.Parse(taskExecutionId);

                try
                {
                    command.ExecuteNonQuery();
                    transaction.Commit();
                }
                catch (SqlException sqlEx)
                {
                    TryRollBack(transaction, sqlEx);
                }
                catch (Exception ex)
                {
                    TryRollback(transaction, ex);
                }
            }

            return response;
        }
        public TaskDefinition EnsureTaskDefinition(TaskId taskId)
        {
            lock (_getTaskObj)
            {
                var taskDefinition = GetTask(taskId);
                if (taskDefinition != null)
                {
                    return taskDefinition;
                }
                else
                {
                    // wait a random amount of time in case two threads or two instances of this repository 
                    // independently belive that the task doesn't exist
                    Thread.Sleep(new Random(Guid.NewGuid().GetHashCode()).Next(2000));
                    taskDefinition = GetTask(taskId);
                    if (taskDefinition != null)
                    {
                        return taskDefinition;
                    }

                    return InsertNewTask(taskId);
                }
            }
        }
        private TaskDefinition InsertNewTask(TaskId taskId)
        {
            using (var connection = CreateNewConnection(taskId))
            {
                using (var command = new SqlCommand(TaskQueryBuilder.InsertTaskQuery, connection))
                {
                    command.Parameters.Add(new SqlParameter("@ApplicationName", SqlDbType.VarChar, 200)).Value = taskId.ApplicationName;
                    command.Parameters.Add(new SqlParameter("@TaskName", SqlDbType.VarChar, 200)).Value = taskId.TaskName;

                    var task = new TaskDefinition();
                    task.TaskDefinitionId = (int)command.ExecuteScalar();

                    string key = taskId.ApplicationName + "::" + taskId.TaskName;

                    lock (_myCacheSyncObj)
                    {
                        CacheTaskDefinition(key, task);
                    }
                    return task;
                }
            }
        }
        private TaskDefinition LoadTask(TaskId taskId)
        {
            using (var connection = CreateNewConnection(taskId))
            {
                using (var command = new SqlCommand(TaskQueryBuilder.GetTaskQuery, connection))
                {
                    command.Parameters.Add(new SqlParameter("@ApplicationName", SqlDbType.VarChar, 200)).Value = taskId.ApplicationName;
                    command.Parameters.Add(new SqlParameter("@TaskName", SqlDbType.VarChar, 200)).Value = taskId.TaskName;
                    using (var reader = command.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            var task = new TaskDefinition();
                            task.TaskDefinitionId = int.Parse(reader["TaskDefinitionId"].ToString());

                            return task;
                        }
                    }
                }
            }

            return null;
        }
 private void RegisterEvent(TaskId taskId, string taskExecutionId, EventType eventType, string message)
 {
     _eventsRepository.LogEvent(taskId, taskExecutionId, eventType, message);
 }
 private void SetTaskExecutionAsFailed(TaskId taskId, string taskExecutionId)
 {
     using (var connection = CreateNewConnection(taskId))
     {
         using (var command = new SqlCommand(TaskQueryBuilder.SetTaskExecutionAsFailedQuery, connection))
         {
             command.CommandTimeout = ConnectionStore.Instance.GetConnection(taskId).QueryTimeoutSeconds;
             command.Parameters.Add(new SqlParameter("@TaskExecutionId", SqlDbType.Int)).Value = int.Parse(taskExecutionId);
             command.ExecuteNonQuery();
         }
     }
 }
        private int CreateOverrideTaskExecution(TaskId taskId, int taskDefinitionId, TimeSpan overrideThreshold, string referenceValue,
            short failedTaskRetryLimit, short deadTaskRetryLimit, string tasklingVersion, string executionHeader)
        {
            using (var connection = CreateNewConnection(taskId))
            {
                using (var command = new SqlCommand(TaskQueryBuilder.InsertKeepAliveTaskExecution, connection))
                {
                    command.CommandText = TaskQueryBuilder.InsertOverrideTaskExecution;
                    command.Parameters.Clear();
                    command.Parameters.Add(new SqlParameter("@TaskDefinitionId", SqlDbType.Int)).Value = taskDefinitionId;
                    command.Parameters.Add(new SqlParameter("@ServerName", SqlDbType.VarChar, 200)).Value = Environment.MachineName;
                    command.Parameters.Add(new SqlParameter("@TaskDeathMode", SqlDbType.TinyInt)).Value = (byte)TaskDeathMode.Override;
                    command.Parameters.Add(new SqlParameter("@OverrideThreshold", SqlDbType.Time)).Value = overrideThreshold;
                    command.Parameters.Add(new SqlParameter("@FailedTaskRetryLimit", SqlDbType.SmallInt)).Value = failedTaskRetryLimit;
                    command.Parameters.Add(new SqlParameter("@DeadTaskRetryLimit", SqlDbType.SmallInt)).Value = deadTaskRetryLimit;
                    command.Parameters.Add(new SqlParameter("@TasklingVersion", SqlDbType.VarChar)).Value = tasklingVersion;

                    if (executionHeader == null)
                        command.Parameters.Add(new SqlParameter("@ExecutionHeader", SqlDbType.NVarChar, -1)).Value = DBNull.Value;
                    else
                        command.Parameters.Add(new SqlParameter("@ExecutionHeader", SqlDbType.NVarChar, -1)).Value = executionHeader;

                    if (referenceValue == null)
                        command.Parameters.Add(new SqlParameter("@ReferenceValue", SqlDbType.NVarChar, 2000)).Value = DBNull.Value;
                    else
                        command.Parameters.Add(new SqlParameter("@ReferenceValue", SqlDbType.NVarChar, 2000)).Value = referenceValue;

                    return (int)command.ExecuteScalar();
                }
            }
        }
        private int CreateKeepAliveTaskExecution(TaskId taskId, int taskDefinitionId, TimeSpan keepAliveInterval, TimeSpan keepAliveDeathThreshold, string referenceValue,
            short failedTaskRetryLimit, short deadTaskRetryLimit, string tasklingVersion, string executionHeader)
        {
            using (var connection = CreateNewConnection(taskId))
            {
                using (var command = new SqlCommand(TaskQueryBuilder.InsertKeepAliveTaskExecution, connection))
                {
                    command.CommandTimeout = ConnectionStore.Instance.GetConnection(taskId).QueryTimeoutSeconds;
                    command.Parameters.Add(new SqlParameter("@TaskDefinitionId", SqlDbType.Int)).Value = taskDefinitionId;
                    command.Parameters.Add(new SqlParameter("@ServerName", SqlDbType.VarChar, 200)).Value = Environment.MachineName;
                    command.Parameters.Add(new SqlParameter("@TaskDeathMode", SqlDbType.TinyInt)).Value = (byte)TaskDeathMode.KeepAlive;
                    command.Parameters.Add(new SqlParameter("@KeepAliveInterval", SqlDbType.Time)).Value = keepAliveInterval;
                    command.Parameters.Add(new SqlParameter("@KeepAliveDeathThreshold", SqlDbType.Time)).Value = keepAliveDeathThreshold;
                    command.Parameters.Add(new SqlParameter("@FailedTaskRetryLimit", SqlDbType.SmallInt)).Value = failedTaskRetryLimit;
                    command.Parameters.Add(new SqlParameter("@DeadTaskRetryLimit", SqlDbType.SmallInt)).Value = deadTaskRetryLimit;
                    command.Parameters.Add(new SqlParameter("@TasklingVersion", SqlDbType.VarChar)).Value = tasklingVersion;

                    if (executionHeader == null)
                        command.Parameters.Add(new SqlParameter("@ExecutionHeader", SqlDbType.NVarChar, -1)).Value = DBNull.Value;
                    else
                        command.Parameters.Add(new SqlParameter("@ExecutionHeader", SqlDbType.NVarChar, -1)).Value = executionHeader;

                    if (referenceValue == null)
                        command.Parameters.Add(new SqlParameter("@ReferenceValue", SqlDbType.NVarChar, 2000)).Value = DBNull.Value;
                    else
                        command.Parameters.Add(new SqlParameter("@ReferenceValue", SqlDbType.NVarChar, 2000)).Value = referenceValue;

                    var taskExecutionId = (int)command.ExecuteScalar();

                    return taskExecutionId;
                }
            }
        }
        private TaskExecutionStartResponse TryGetExecutionToken(TaskId taskId, int taskDefinitionId, int taskExecutionId, int concurrencyLimit)
        {
            var tokenRequest = new TokenRequest()
            {
                TaskId = taskId,
                TaskDefinitionId = taskDefinitionId,
                TaskExecutionId = taskExecutionId.ToString(),
                ConcurrencyLimit = concurrencyLimit
            };

            var tokenResponse = _executionTokenRepository.TryAcquireExecutionToken(tokenRequest);

            var response = new TaskExecutionStartResponse();
            response.ExecutionTokenId = tokenResponse.ExecutionTokenId;
            response.GrantStatus = tokenResponse.GrantStatus;
            response.StartedAt = tokenResponse.StartedAt;
            response.TaskExecutionId = taskExecutionId.ToString();

            return response;
        }
 private TaskDefinition GetTask(TaskId taskId)
 {
     return GetCachedDefinition(taskId);
 }
        private TaskDefinition GetCachedDefinition(TaskId taskId)
        {
            lock (_myCacheSyncObj)
            {
                string key = taskId.ApplicationName + "::" + taskId.TaskName;

                if (_cachedTaskDefinitions.ContainsKey(key))
                {
                    var definition = _cachedTaskDefinitions[key];
                    if ((definition.CachedAt - DateTime.UtcNow).TotalSeconds < 300)
                        return definition.TaskDefinition;
                }
                else
                {
                    var task = LoadTask(taskId);
                    CacheTaskDefinition(key, task);
                    return task;
                }
            }

            return null;
        }
        private bool TryAcquireCriticalSection(TaskId taskId, int taskDefinitionId, string taskExecutionId, CriticalSectionType criticalSectionType)
        {
            bool granted = false;

            using (var connection = CreateNewConnection(taskId))
            {
                SqlTransaction transaction = connection.BeginTransaction(IsolationLevel.Serializable);

                var command = connection.CreateCommand();
                command.Transaction = transaction;
                command.CommandTimeout = ConnectionStore.Instance.GetConnection(taskId).QueryTimeoutSeconds; ;

                try
                {
                    AcquireRowLock(taskDefinitionId, taskExecutionId, command);
                    var csState = GetCriticalSectionState(taskDefinitionId, criticalSectionType, command);
                    CleanseOfExpiredExecutions(csState, command);

                    if (csState.IsGranted)
                    {
                        // if the critical section is still granted to another execution after cleansing
                        // then we rejected the request. If the execution is not in the queue then we add it
                        if (!csState.ExistsInQueue(taskExecutionId))
                            csState.AddToQueue(taskExecutionId);

                        granted = false;
                    }
                    else
                    {
                        if (csState.GetQueue().Any())
                        {
                            if (csState.GetFirstExecutionIdInQueue() == taskExecutionId)
                            {
                                GrantCriticalSection(csState, taskDefinitionId, taskExecutionId, command);
                                csState.RemoveFirstInQueue();
                                granted = true;
                            }
                            else
                            {
                                // not next in queue so cannot be granted the critical section
                                granted = false;
                            }
                        }
                        else
                        {
                            GrantCriticalSection(csState, taskDefinitionId, taskExecutionId, command);
                            granted = true;
                        }
                    }

                    if (csState.HasBeenModified)
                        UpdateCriticalSectionState(taskDefinitionId, csState, criticalSectionType, command);

                    transaction.Commit();
                }
                catch (SqlException sqlEx)
                {
                    TryRollBack(transaction, sqlEx);
                }
                catch (Exception ex)
                {
                    TryRollback(transaction, ex);
                }
            }

            return granted;
        }