У меня есть приложение, которое выполняет рабочие процессы, используя WorkflowApplication, а также делает другие вещи.Я хотел бы, чтобы и эти другие вещи, и взаимодействия WorkflowApplication с хранилищем экземпляров до вызова BeginRun () были ограничены транзакцией, поэтому я все обернул в одну.Однако введение этой транзакции приводит к зависанию таких вызовов, как WorkflowApplication.Persist ().Следующий пример представляет собой модифицированную версию базового образца персистентности экземпляра (описано здесь , загрузка с здесь ).Я изменил оригинал, определив область видимости всего сделанного в транзакции;это очень похоже на то, что делает мое приложение.
using System;
using System.Activities;
using System.Activities.DurableInstancing;
using System.Activities.Statements;
using System.Runtime.DurableInstancing;
using System.Threading;
namespace Microsoft.Samples.Activities
{
using System.Transactions;
class Program
{
static AutoResetEvent instanceUnloaded = new AutoResetEvent(false);
static Activity activity = CreateWorkflow();
static Guid id;
const string readLineBookmark = "ReadLine1";
static void Main()
{
StartAndUnloadInstance();
LoadAndCompleteInstance();
Console.WriteLine("Press [Enter] to exit.");
Console.ReadLine();
}
static void StartAndUnloadInstance()
{
using (TransactionScope ts = new TransactionScope(TransactionScopeOption.RequiresNew))
{
WorkflowApplication application = new WorkflowApplication(activity);
InstanceHandle handle;
application.InstanceStore = SetupInstanceStore(out handle);
application.Completed = (e) =>
{ handle.Free(); };
application.PersistableIdle = (e) =>
{
return PersistableIdleAction.Unload;
};
application.Unloaded = (e) =>
{
instanceUnloaded.Set();
};
application.Persist();
id = application.Id;
application.Run();
ts.Complete();
}
instanceUnloaded.WaitOne();
}
static void LoadAndCompleteInstance()
{
using (TransactionScope ts = new TransactionScope(TransactionScopeOption.RequiresNew))
{
string input = Console.ReadLine();
WorkflowApplication application = new WorkflowApplication(activity);
InstanceHandle handle;
application.InstanceStore = SetupInstanceStore(out handle);
application.Completed = (workflowApplicationCompletedEventArgs) =>
{
handle.Free();
Console.WriteLine(
"\nWorkflowApplication has Completed in the {0} state.",
workflowApplicationCompletedEventArgs.CompletionState);
};
application.Unloaded = (workflowApplicationEventArgs) =>
{
Console.WriteLine("WorkflowApplication has Unloaded\n");
instanceUnloaded.Set();
};
application.Load(id);
//this resumes the bookmark setup by readline
application.ResumeBookmark(readLineBookmark, input);
ts.Complete();
}
instanceUnloaded.WaitOne();
}
static Sequence CreateWorkflow()
{
Variable<string> response = new Variable<string>();
return new Sequence()
{
Variables = { response },
Activities = {
new WriteLine(){
Text = new InArgument<string>("What is your name?")},
new ReadLine(){
BookmarkName = readLineBookmark,
Result = new OutArgument<string>(response)},
new WriteLine(){
Text = new InArgument<string>((context) => "Hello " + response.Get(context))}}
};
}
private static InstanceStore SetupInstanceStore(out InstanceHandle handle)
{
SqlWorkflowInstanceStore instanceStore =
new SqlWorkflowInstanceStore(@"Data Source=.;Initial Catalog=SampleInstanceStore;Integrated Security=True;Asynchronous Processing=True");
handle = instanceStore.CreateInstanceHandle();
InstanceView view = instanceStore.Execute(handle, new CreateWorkflowOwnerCommand(), TimeSpan.FromSeconds(30));
instanceStore.DefaultInstanceOwner = view.InstanceOwner;
return instanceStore;
}
}
}
using System;
using System.Activities;
using System.Activities.DurableInstancing;
using System.Activities.Statements;
using System.Runtime.DurableInstancing;
using System.Threading;
namespace Microsoft.Samples.Activities
{
using System.Transactions;
class Program
{
static AutoResetEvent instanceUnloaded = new AutoResetEvent(false);
static Activity activity = CreateWorkflow();
static Guid id;
const string readLineBookmark = "ReadLine1";
static void Main()
{
StartAndUnloadInstance();
LoadAndCompleteInstance();
Console.WriteLine("Press [Enter] to exit.");
Console.ReadLine();
}
static void StartAndUnloadInstance()
{
using (TransactionScope ts = new TransactionScope(TransactionScopeOption.RequiresNew))
{
WorkflowApplication application = new WorkflowApplication(activity);
InstanceHandle handle;
application.InstanceStore = SetupInstanceStore(out handle);
application.Completed = (e) =>
{ handle.Free(); };
application.PersistableIdle = (e) =>
{
return PersistableIdleAction.Unload;
};
application.Unloaded = (e) =>
{
instanceUnloaded.Set();
};
application.Persist();
id = application.Id;
application.Run();
ts.Complete();
}
instanceUnloaded.WaitOne();
}
static void LoadAndCompleteInstance()
{
using (TransactionScope ts = new TransactionScope(TransactionScopeOption.RequiresNew))
{
string input = Console.ReadLine();
WorkflowApplication application = new WorkflowApplication(activity);
InstanceHandle handle;
application.InstanceStore = SetupInstanceStore(out handle);
application.Completed = (workflowApplicationCompletedEventArgs) =>
{
handle.Free();
Console.WriteLine(
"\nWorkflowApplication has Completed in the {0} state.",
workflowApplicationCompletedEventArgs.CompletionState);
};
application.Unloaded = (workflowApplicationEventArgs) =>
{
Console.WriteLine("WorkflowApplication has Unloaded\n");
instanceUnloaded.Set();
};
application.Load(id);
//this resumes the bookmark setup by readline
application.ResumeBookmark(readLineBookmark, input);
ts.Complete();
}
instanceUnloaded.WaitOne();
}
static Sequence CreateWorkflow()
{
Variable<string> response = new Variable<string>();
return new Sequence()
{
Variables = { response },
Activities = {
new WriteLine(){
Text = new InArgument<string>("What is your name?")},
new ReadLine(){
BookmarkName = readLineBookmark,
Result = new OutArgument<string>(response)},
new WriteLine(){
Text = new InArgument<string>((context) => "Hello " + response.Get(context))}}
};
}
private static InstanceStore SetupInstanceStore(out InstanceHandle handle)
{
SqlWorkflowInstanceStore instanceStore =
new SqlWorkflowInstanceStore(@"Data Source=.;Initial Catalog=SampleInstanceStore;Integrated Security=True;Asynchronous Processing=True");
handle = instanceStore.CreateInstanceHandle();
InstanceView view = instanceStore.Execute(handle, new CreateWorkflowOwnerCommand(), TimeSpan.FromSeconds(30));
instanceStore.DefaultInstanceOwner = view.InstanceOwner;
return instanceStore;
}
}
}
При запуске приложение зависает при вызове Persist () в StartAndUnloadInstance ().Зависание заканчивается примерно через пять минут (где-то есть тайм-аут).Пока вы зависли, вы можете увидеть причину, посмотрев на Activity Monitor в SQL Server.Вызов для создания владельца рабочего процесса в SetupInstanceStore () получает эксклюзивную блокировку для строки в LockOwnersTable.Вызов Persist () пытается получить такую же блокировку.К сожалению.
В любом случае, более широкий вопрос, как указано в заголовке: может ли экземпляр хранилища взаимодействий, которые я делаю до вызова BeginRun (), работать в контексте внешней транзакции или нет?Если так, что я делаю не так?Если нет, какие варианты у меня есть?До сих пор я был в состоянии устранить зависание / тупик, окружив каждый случай, когда WorkflowApplication обращается к хранилищу экземпляров с помощью:
using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Suppress))
{
// Method call that interacts with the instance store.
ts.Complete();
}
Это немного продвигает меня вперед, но сводит меня к написанию кода компенсации для обработки этих вызововтерпит неудачу.Это не должно быть необходимым.Мы будем благодарны за понимание.
РЕДАКТИРОВАТЬ : Для более подробного описания я хочу, чтобы рабочий процесс сохранялся до выполнения в той же транзакции, что и другие операции с базой данных.Я хочу это:
- Разрешить повторный запуск рабочего процесса, если во время выполнения рабочего процесса умирает хост-процесс.
- Убедитесь, что откат персистентности и рабочий процесс отмененыникогда не запускается, если происходит сбой другой активности базы данных.
Сам рабочий процесс не нужно запускать в транзакции, только взаимодействия хранилища экземпляров, которые происходят до вызова BeginRun ().