我当前的流程以下列方式运行:
1。)用户在前端应用程序中输入URL以进行分析
2。)前端验证URL并在包含URL属性的表中创建URL记录
3。)前端创建/更新表中的一行,用于跟踪URL所处的处理阶段(每个URL都有自己的内部ID)
3.A)状态代码更新为“排队”状态
----表定义:
ID INT PRIMARY KEY,
StatusCode INT,
StatusDescription VARCHAR(MAX),
IsInitial BIT,
LastUpdated DATETIME
4.。)前端向Azure存储队列发送包含提交的URL内部ID的消息
将第一封邮件发送到队列后------------>
4.A)在UI中创建一个对象供用户点击(“刷新”数据)
4.B)用户在创建的对象上点击(很可能会发生这种情况)(如果经过验证,则立即点击)
4.C)另一条消息被发送到包含URL ID
的队列< --------------------------------
5.。)运行azure webjob(后台任务)持续选择这些消息并开始处理
6。)webjob确定此URL是否可以处理
.....如果
,就可以开始处理了.....如果退出
一旦确定被认为可以继续......
在流程的最后,LastUpdated更新为当前时间
try catch围绕着这个过程
a。)如果进程出错,则更新状态代码以反映
b。)新消息被推入队列以进行重试
确定网址是否可以解析的功能:
private bool IsReadyToParse(int [ID])
{
using (var db = EntityFactory.GetInstance())
{
var item = db.ProcessStatus.FirstOrDefault(x => x.ID == [ID]);
if (item == null || item.StatusCode > 1)
{
return false;
}
if (item.StatusCode == (int)ProcessStatusEnum.Error || item.LastUpdated == null)
{
item.LastUpdated = DateTime.Now;
db.Entry(item).State = EntityState.Modified;
db.SaveChanges();
return true;
}
return ((DateTime)item.LastUpdated).AddMinutes(15) < DateTime.Now;
}
}
队列消息通过此功能进入:
// This function will get triggered/executed when a new message is written
// on an Azure Queue
public static void ProcessQueueMessage([QueueTrigger("[queue]")] QueueItem item, TextWriter log)
{
Console.WriteLine("Item found! Starting services [Id: {0}]", item.ID);
Agent agent = new Agent([ID], log);
agent.StartProcessing();
log.WriteLine([Item]);
}
...现在的问题是,这个持续运行的webjob一次可以收到多条消息(我希望将其扩展到另外几个从同一队列中读取的webjobs)
我如何确定函数IsReadyToParse()实际上反映了当前的处理状态?
如果数据库只是要将状态代码更新为“进行中”,但是另一个线程只是读取状态代码并且还可以继续执行该过程怎么办?
答案 0 :(得分:0)
这是我有限的开发人员测试的基本解决方案...随着我的进展将会更新。
...... 使用此存储过程而不是IsReadyToParse()
CREATE PROCEDURE dbo.usp_getIsReadyForProcess
@[ID] INT
AS
BEGIN
BEGIN TRY
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION
DECLARE @lastUpdated DATETIME
DECLARE @statusCode INT
-- LOCK ROW UNTIL END OF TRANSACTION
SET @lastUpdated = (SELECT LastUpdated FROM dbo.ProcessStatus WITH (ROWLOCK, HOLDLOCK) WHERE [ID] = @[ID])
SET @statusCode = (SELECT StatusCode FROM dbo.ProcessStatus WHERE [ID] = @[ID])
DECLARE @isReady BIT
--If there is no row count
IF @@ROWCOUNT = 0
BEGIN
SET @isReady = 0
END
-- If video is already in process
ELSE IF @statusCode > 1
BEGIN
SET @isReady = 0
END
-- If this is the first time it is getting parsed
ELSE IF @lastUpdated IS NULL
BEGIN
SET @isReady = 1
--Update datetime field
UPDATE dbo.ProcessStatus
SET LastUpdated = GETDATE()
WHERE [ID] = @[ID]
END
-- If is isnt the initial parse and hasnt been 15 minutes yet
ELSE IF GETDATE() < DATEADD(MINUTE, 15, @lastUpdated)
BEGIN
SET @isReady = 0
END
-- Anything else, and its a go
ELSE
BEGIN
SET @isReady = 1
END
-- If were ready to start, update the status code
IF @isReady = 1
BEGIN
UPDATE dbo.ProcessStatus
SET StatusCode = 2
WHERE [ID] = @[ID]
END
COMMIT TRANSACTION
SELECT @isReady
END TRY
BEGIN CATCH
-- If there was any type of error
ROLLBACK
SELECT 0
END CATCH
END
答案 1 :(得分:0)
这是一种可能的方法,类似于WebJobs SDK在内部执行的操作,以防止更多的webjob函数同时处理相同的blob触发器。
当函数从队列中获取消息时,请创建一个与消息中的ID同名的blob。 blob的内容是处理的状态(Done或InProgress)。当一个函数想要处理带有该ID的消息时,它必须对该blob进行租约 - 这可以保证线程的安全性。然后:
如果处理邮件的时间超过60秒,您将需要一些额外的代码来续订blob租约,否则它将会过期而其他人可以将其提取。