我有一个奇怪的问题,有状态服务超时,只有当被另一个服务调用到下游时。
这个项目的想法是记录节点之间的跳跃延迟,给定n个跳数。实施在3个项目中:
API - 向工作人员下游调用
工作服务 - 递减计数并调用另一个WorkerService
结果服务 - 记录API要提取的结果。
该解决方案在内部部署和Azure云中都会引发异常,但在本地完美运行。
实现:
internal sealed class WorkerService : StatelessService, IHopWorker
{
public WorkerService(StatelessServiceContext context)
: base(context)
{ }
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
return this.CreateServiceRemotingInstanceListeners();
}
public async Task Hop(HopCounter counter)
{
counter.HopCount = counter.HopCount - 1;
counter.JunctionIds.Add(Context.NodeContext.NodeId.ToString());
if (counter.HopCount < 1)
{
counter.Completed = DateTime.Now;
await new ServiceProxyFactory().CreateServiceProxy<IResultService>(new Uri("fabric:/AsfNetworkHops/ResultsService"), new ServicePartitionKey("Data")).AddResults(counter);
}
else
{
await new ServiceProxyFactory().CreateServiceProxy<IHopWorker>(new Uri("fabric:/AsfNetworkHops/WorkerService"), targetReplicaSelector: TargetReplicaSelector.RandomInstance).Hop(counter);
}
}
}
结果服务
internal sealed class ResultsService : StatefulService, IResultService
{
Task<IReliableDictionary<string, HopCounter>> Results => StateManager.GetOrAddAsync<IReliableDictionary<string, HopCounter>>("results");
public ResultsService(StatefulServiceContext context)
: base(context, new ReliableStateManager(context, new ReliableStateManagerConfiguration(
new ReliableStateManagerReplicatorSettings
{
MaxReplicationMessageSize = 1073741824
})))
{
}
protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
{
return this.CreateServiceRemotingReplicaListeners();
}
public async Task AddResults(HopCounter counter)
{
using (var transcation = StateManager.CreateTransaction())
{
var results = await Results;
await results.AddAsync(transcation, Guid.NewGuid().ToString(), counter);
await transcation.CommitAsync();
}
}
public async Task<HopCounter[]> GetResults()
{
IList<HopCounter> results = new List<HopCounter>();
using (var tx = StateManager.CreateTransaction())
{
var res = await Results;
var enumerator = (await res.CreateEnumerableAsync(tx)).GetAsyncEnumerator();
while (await enumerator.MoveNextAsync(new CancellationToken()))
{
results.Add(enumerator.Current.Value);
}
await tx.CommitAsync();
return results.ToArray();
}
}
}
API图层
[Route("api/[controller]")]
public class HopController : Controller
{
[HttpGet]
[Route("health")]
public IActionResult Health()
{
return Ok("OK");
}
[HttpGet]
[Route("start")]
public async Task<IActionResult> Start(int hopCount = 10)
{
try
{
var counter = new HopCounter();
counter.HopCount = hopCount;
counter.Initiated = DateTime.Now;
IHopWorker worker = null;
try
{
worker = new ServiceProxyFactory().CreateServiceProxy<IHopWorker>(new Uri("fabric:/AsfNetworkHops/WorkerService"));
}
catch (Exception excep)
{
return Ok($"Error creating proxy {excep.Message} {excep.StackTrace}");
}
await worker.Hop(counter);
return Ok();
}
catch (Exception excep)
{
return Ok(excep);
}
}
[HttpGet]
[Route("results")]
public async Task<IActionResult> Results()
{
try
{
IResultService results = null;
try
{
results = new ServiceProxyFactory().CreateServiceProxy<IResultService>(
new Uri("fabric:/AsfNetworkHops/ResultsService"), new ServicePartitionKey("Data"));
}
catch (Exception excep)
{
return Ok($"Error creating proxy {excep.Message} {excep.StackTrace}");
}
return Ok(await results.GetResults());
}
catch (Exception excep)
{
return Ok(excep);
}
}
}
App Manifest:
<ApplicationManifest xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ApplicationTypeName="AsfNetworkHopsType" ApplicationTypeVersion="1.0.0" xmlns="http://schemas.microsoft.com/2011/01/fabric">
<Parameters>
<Parameter Name="ResultsService_MinReplicaSetSize" DefaultValue="3" />
<Parameter Name="ResultsService_PartitionCount" DefaultValue="1" />
<Parameter Name="ResultsService_TargetReplicaSetSize" DefaultValue="3" />
<Parameter Name="NetworkHopsAPI_InstanceCount" DefaultValue="-1" />
<Parameter Name="WorkerService_InstanceCount" DefaultValue="-1" />
</Parameters>
<!-- Import the ServiceManifest from the ServicePackage. The ServiceManifestName and ServiceManifestVersion
should match the Name and Version attributes of the ServiceManifest element defined in the
ServiceManifest.xml file. -->
<ServiceManifestImport>
<ServiceManifestRef ServiceManifestName="ResultsServicePkg" ServiceManifestVersion="1.0.0" />
<ConfigOverrides />
</ServiceManifestImport>
<ServiceManifestImport>
<ServiceManifestRef ServiceManifestName="NetworkHopsAPIPkg" ServiceManifestVersion="1.0.0" />
<ConfigOverrides />
</ServiceManifestImport>
<ServiceManifestImport>
<ServiceManifestRef ServiceManifestName="WorkerServicePkg" ServiceManifestVersion="1.0.0" />
<ConfigOverrides />
</ServiceManifestImport>
<DefaultServices>
<!-- The section below creates instances of service types, when an instance of this
application type is created. You can also create one or more instances of service type using the
ServiceFabric PowerShell module.
The attribute ServiceTypeName below must match the name defined in the imported ServiceManifest.xml file. -->
<Service Name="ResultsService" ServicePackageActivationMode="ExclusiveProcess">
<StatefulService ServiceTypeName="ResultsServiceType" TargetReplicaSetSize="[ResultsService_TargetReplicaSetSize]" MinReplicaSetSize="[ResultsService_MinReplicaSetSize]">
<NamedPartition>
<Partition Name="Data" />
</NamedPartition>
</StatefulService>
</Service>
<Service Name="NetworkHopsAPI" ServicePackageActivationMode="ExclusiveProcess">
<StatelessService ServiceTypeName="NetworkHopsAPIType" InstanceCount="[NetworkHopsAPI_InstanceCount]">
<SingletonPartition />
</StatelessService>
</Service>
<Service Name="WorkerService" ServicePackageActivationMode="ExclusiveProcess">
<StatelessService ServiceTypeName="WorkerServiceType" InstanceCount="[WorkerService_InstanceCount]">
<SingletonPartition />
</StatelessService>
</Service>
</DefaultServices>
</ApplicationManifest>
DTO
[DataContract]
[Serializable]
public class HopCounter
{
[DataMember]
private DateTime _completed;
[DataMember]
public DateTime Initiated { get; set; }
[DataMember]
public DateTime Completed
{
get { return _completed; }
set
{
_completed = value;
MilisecondsTaken = (Completed - Initiated).Milliseconds;
}
}
[DataMember]
public int HopCount { get; set; }
[DataMember]
public List<string> JunctionIds { get; set; } = new List<string>();
[DataMember]
public bool WorkerOnly { get; set; }
[DataMember]
public double MilisecondsTaken { get; set; }
}
仅在调用Results Service时发生超时,否则返回HTTP 200
这种情况发生在.Net Core&amp; .Net 4.6.1所以必须是我正在使用的模式,但它对我来说似乎是一种非常普通的访问模式。
我有一个示例应用程序here。
有人可以帮忙吗?
错误是:
操作已超时。在 Microsoft.ServiceFabric.Replicator.DynamicStateManager.d__188.MoveNext() ---从抛出异常的先前位置开始的堆栈跟踪结束--- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务) Microsoft.ServiceFabric.Replicator.DynamicStateManager.d__187.MoveNext() ---从抛出异常的先前位置开始的堆栈跟踪结束--- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务) Microsoft.ServiceFabric.Replicator.DynamicStateManager.d__170.MoveNext() ---从抛出异常的先前位置开始的堆栈跟踪结束--- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务) Microsoft.ServiceFabric.Replicator.DynamicStateManager.d__109
1.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.ServiceFabric.Data.ReliableStateManagerImpl.<Microsoft-ServiceFabric-Data-IReliableStateManager-GetOrAddAsync>d__23
1.MoveNext() ---从抛出异常的先前位置开始的堆栈跟踪结束--- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务) Microsoft.ServiceFabric.Data.ReliableStateManagerImpl.d__251.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter
1.GetResult() 在Results.Results.d__4.MoveNext()中 C:\ dev \ asf-latency \ Results \ Results.cs:第42行