C# SqlWorkflowInstanceStore WaitForEvents返回HasRunnableWorkflowEvent,但LoadRunnableInstance失败
亲爱的 请帮助我恢复延迟(和持续)的工作流 我正在检查自托管工作流商店是否有任何实例被延迟并可以恢复。出于测试目的,我创建了一个延迟的虚拟活动,它会在延迟时持续存在 通常,恢复过程如下所示:C# SqlWorkflowInstanceStore WaitForEvents返回HasRunnableWorkflowEvent,但LoadRunnableInstance失败,c#,workflow-foundation-4,C#,Workflow Foundation 4,亲爱的 请帮助我恢复延迟(和持续)的工作流 我正在检查自托管工作流商店是否有任何实例被延迟并可以恢复。出于测试目的,我创建了一个延迟的虚拟活动,它会在延迟时持续存在 通常,恢复过程如下所示: get WF definition configure sql instance store call WaitForEvents is there event with HasRunnableWorkflowEvent.Value name and if it is create WorkflowApp
get WF definition
configure sql instance store
call WaitForEvents
is there event with HasRunnableWorkflowEvent.Value name and if it is
create WorkflowApplication object and execute LoadRunnableInstance method
如果创建了存储|初始化,调用了WaitForEvents,存储关闭,那么它工作正常。在这种情况下,存储从持久化数据库读取所有可用的工作流,并在没有可恢复的工作流时抛出超时异常
如果只为WaitForEvents
创建存储并启动循环,则会出现此问题(在BeginWaitForEvents
中也会发生同样的情况)。在这种情况下,它将从DB
读取所有可用的工作流
(使用正确的ID),但随后它将不再读取超时异常
,而是再读取一个实例(我确切地知道有多少工作流
,因为使用单独的测试数据库
)。但是无法读取并且抛出InstanceNotradeyException
。在catch
中,我正在检查workflowApplication.Id
,但它以前没有与我的测试一起保存
我尝试在新的(空的)持久数据库上运行,结果相同:(
此代码失败:
using (var storeWrapper = new StoreWrapper(wf, connStr))
for (int q = 0; q < 5; q++)
{
var id = Resume(storeWrapper); // InstanceNotReadyException here when all activities is resumed
下面是我用于测试的存储包装定义:
public class StoreWrapper : IDisposable
{
Activity WfDefinition { get; set; }
public static readonly XName WorkflowHostTypePropertyName = XNamespace.Get("urn:schemas-microsoft-com:System.Activities/4.0/properties").GetName("WorkflowHostType");
public StoreWrapper(Activity wfDefinition, string connectionStr)
{
_store = new SqlWorkflowInstanceStore(connectionStr);
HostTypeName = XName.Get(wfDefinition.DisplayName, "ttt.workflow");
WfDefinition = wfDefinition;
}
SqlWorkflowInstanceStore _store;
public SqlWorkflowInstanceStore GetStore()
{
if (Handle == null)
{
InitStore(_store, WfDefinition);
Handle = _store.CreateInstanceHandle();
var view = _store.Execute(Handle, new CreateWorkflowOwnerCommand
{
InstanceOwnerMetadata = { { WorkflowHostTypePropertyName, new InstanceValue(HostTypeName) } }
}, TimeSpan.FromSeconds(30));
_store.DefaultInstanceOwner = view.InstanceOwner;
//Trace.WriteLine(string.Format("{0} owns {1}", view.InstanceOwner.InstanceOwnerId, HostTypeName));
}
return _store;
}
protected virtual void InitStore(SqlWorkflowInstanceStore store, Activity wfDefinition)
{
}
public InstanceHandle Handle { get; protected set; }
XName HostTypeName { get; set; }
public void Dispose()
{
if (Handle != null)
{
var deleteOwner = new DeleteWorkflowOwnerCommand();
//Trace.WriteLine(string.Format("{0} frees {1}", Store.DefaultInstanceOwner.InstanceOwnerId, HostTypeName));
_store.Execute(Handle, deleteOwner, TimeSpan.FromSeconds(30));
Handle.Free();
Handle = null;
_store = null;
}
}
public WorkflowApplication GetApplication()
{
var wfApp = new WorkflowApplication(WfDefinition);
wfApp.InstanceStore = GetStore();
wfApp.PersistableIdle = e => PersistableIdleAction.Persist;
Dictionary<XName, object> wfScope = new Dictionary<XName, object> { { WorkflowHostTypePropertyName, HostTypeName } };
wfApp.AddInitialInstanceValues(wfScope);
return wfApp;
}
}
公共类StoreWrapper:IDisposable
{
活动定义{get;set;}
公共静态只读XName WorkflowHostTypePropertyName=XNamespace.Get(“urn:schemas-microsoft-com:System.Activities/4.0/properties”).GetName(“WorkflowHostType”);
public StoreWrapper(活动定义,字符串连接)
{
_store=新的SqlWorkflowInstanceStore(connectionStr);
HostTypeName=XName.Get(wfDefinition.DisplayName,“ttt.workflow”);
WfDefinition=WfDefinition;
}
SqlWorkflowInstanceStore;
公共SqlWorkflowInstanceStore GetStore()
{
if(Handle==null)
{
InitStore(_store,WfDefinition);
句柄=_store.CreateInstanceHandle();
var view=_store.Execute(句柄,新的CreateWorkflowOwnerCommand
{
InstanceOwnerMetadata={{WorkflowHostTypePropertyName,新InstanceValue(HostTypeName)}
}时距秒(30));
_store.DefaultInstanceOwner=view.InstanceOwner;
//WriteLine(string.Format(“{0}拥有{1}”,view.InstanceOwner.InstanceOwnerId,HostTypeName));
}
退货店;
}
受保护的虚拟void InitStore(SqlWorkflowInstanceStore,活动wfDefinition)
{
}
公共InstanceHandle句柄{get;protected set;}
XName HostTypeName{get;set;}
公共空间处置()
{
if(句柄!=null)
{
var deleteOwner=新的DeleteWorkflowOwnerCommand();
//WriteLine(string.Format(“{0}释放{1}”,Store.DefaultInstanceOwner.InstanceOwnerId,HostTypeName));
_store.Execute(Handle,deleteOwner,TimeSpan.FromSeconds(30));
Handle.Free();
Handle=null;
_store=null;
}
}
公共工作流应用程序GetApplication()
{
var wfApp=新的工作流应用程序(WfDefinition);
wfApp.InstanceStore=GetStore();
wfApp.PersistableIdle=e=>PersistableIdleAction.Persist;
Dictionary wfScope=新字典{{WorkflowHostTypePropertyName,HostTypeName};
wfApp.附加初始值(wfScope);
返回wfApp;
}
}
我不是工作流基础专家,所以我的答案是基于微软的官方例子。第一个是第二个。在这两个示例中,你会找到类似于你的代码,即:
try
{
wfApp.LoadRunnableInstance();
...
}
catch (InstanceNotReadyException)
{
//Some logging
}
考虑到这一点,答案是你是对的,InstanceNodeException
的空捕获是一个很好的解决方案。对基本问题投了赞成票。希望你能得到更多的关注。事实上,我认为,尽管你的+150
慷慨大方,但你的问题受到较少关注可能有两个原因。(1)使用工作流
的人不多,(2)您要求的是最佳解决方案
,它可能更适合于代码审查而不是堆栈溢出,(3)这是一个很小的问题,但您的测试代码很长,没有有意义的解释(如果人们真的可以直接从中复制您的问题,这是可以的,但否则会阻碍代码阅读)。希望你能得到答案…失败循环和未失败循环是两件独立的事情,一件是为每次迭代启动一个新的StoreWrapper。另一件是为每次迭代重用一个StoreWrapper。很久以前我使用了工作流,但看到代码让我觉得你的StoreWrapper不是一个reuse因此,您可以考虑使用工作循环。或者它会引起其他问题吗?@ TracARIN可以用普通的Sql WorkFraseStestOrror重写样本,但是问题将持续下去。我在Web中看到了使用相同的Sql WorkFraseStestOrnStor实例来查询WF数据库运行就绪的工作流的示例。循环中有新实例,但我担心这会导致额外的内存开销和时间延迟。
public class StoreWrapper : IDisposable
{
Activity WfDefinition { get; set; }
public static readonly XName WorkflowHostTypePropertyName = XNamespace.Get("urn:schemas-microsoft-com:System.Activities/4.0/properties").GetName("WorkflowHostType");
public StoreWrapper(Activity wfDefinition, string connectionStr)
{
_store = new SqlWorkflowInstanceStore(connectionStr);
HostTypeName = XName.Get(wfDefinition.DisplayName, "ttt.workflow");
WfDefinition = wfDefinition;
}
SqlWorkflowInstanceStore _store;
public SqlWorkflowInstanceStore GetStore()
{
if (Handle == null)
{
InitStore(_store, WfDefinition);
Handle = _store.CreateInstanceHandle();
var view = _store.Execute(Handle, new CreateWorkflowOwnerCommand
{
InstanceOwnerMetadata = { { WorkflowHostTypePropertyName, new InstanceValue(HostTypeName) } }
}, TimeSpan.FromSeconds(30));
_store.DefaultInstanceOwner = view.InstanceOwner;
//Trace.WriteLine(string.Format("{0} owns {1}", view.InstanceOwner.InstanceOwnerId, HostTypeName));
}
return _store;
}
protected virtual void InitStore(SqlWorkflowInstanceStore store, Activity wfDefinition)
{
}
public InstanceHandle Handle { get; protected set; }
XName HostTypeName { get; set; }
public void Dispose()
{
if (Handle != null)
{
var deleteOwner = new DeleteWorkflowOwnerCommand();
//Trace.WriteLine(string.Format("{0} frees {1}", Store.DefaultInstanceOwner.InstanceOwnerId, HostTypeName));
_store.Execute(Handle, deleteOwner, TimeSpan.FromSeconds(30));
Handle.Free();
Handle = null;
_store = null;
}
}
public WorkflowApplication GetApplication()
{
var wfApp = new WorkflowApplication(WfDefinition);
wfApp.InstanceStore = GetStore();
wfApp.PersistableIdle = e => PersistableIdleAction.Persist;
Dictionary<XName, object> wfScope = new Dictionary<XName, object> { { WorkflowHostTypePropertyName, HostTypeName } };
wfApp.AddInitialInstanceValues(wfScope);
return wfApp;
}
}
try
{
wfApp.LoadRunnableInstance();
...
}
catch (InstanceNotReadyException)
{
//Some logging
}