我们在Azure VM上运行两个Raven服务器,这些服务器彼此复制。偶尔,我们会遇到复制冲突。我们有一个冲突侦听器,它可以在文档的两个版本的内容相同的情况下自动解决冲突。我们还在两台机器上运行脚本,检查冲突并报告它们。
我们今天在以下某个服务器中发生了错误,其中包含以下堆栈跟踪:
Raven.Client.Connection.ServerClient.<DirectQuery>b__77(String conflictedResultId):0
Raven.Client.Connection.ServerClient.AssertNonConflictedDocumentAndCheckIfNeedToReload(RavenJObject docResult, Func`2 onConflictedQueryResult):110
Raven.Client.Connection.ServerClient+<>c__DisplayClass94`1.<RetryOperationBecauseOfConflict>b__93(Boolean current, RavenJObject docResult):0
System.Linq.Enumerable.Aggregate[TSource,TAccumulate](IEnumerable`1 source, TAccumulate seed, Func`3 func):46
Raven.Client.Connection.ServerClient.RetryOperationBecauseOfConflict[T](IEnumerable`1 docResults, T currentResult, Func`1 nextTry, Func`2 onConflictedQueryResult):35
Raven.Client.Connection.ServerClient.DirectQuery(String index, IndexQuery query, OperationMetadata operationMetadata, String[] includes, Boolean metadataOnly, Boolean includeEntries):579
Raven.Client.Connection.ServerClient+<>c__DisplayClass62.<Query>b__61(OperationMetadata u):0
Raven.Client.Connection.ReplicationInformer.TryOperation[T](Func`2 operation, OperationMetadata operationMetadata, OperationMetadata primaryOperationMetadata, Boolean avoidThrowing, T& result, Boolean& wasTimeout):200
Raven.Client.Connection.ReplicationInformer.ExecuteWithReplication[T](String method, String primaryUrl, OperationCredentials primaryCredentials, Int32 currentRequest, Int32 currentReadStripingBase, Func`2 operation):193
Raven.Client.Connection.ServerClient.ExecuteWithReplication[T](String method, Func`2 operation):44
Raven.Client.Document.AbstractDocumentQuery`2.ExecuteActualQuery():65
Raven.Client.Document.AbstractDocumentQuery`2.get_QueryResult():6
Raven.Client.Linq.RavenQueryProviderProcessor`1.ExecuteQuery[TProjection]():123
Raven.Client.Linq.RavenQueryInspector`1.GetEnumerator():0
在针对其中一个集合的Lucene查询期间发生异常。堆栈跟踪表明遇到了冲突。对AssertNonConflictedAndCheckIfNeedToReload
的呼吁表明冲突得到了解决。目前机器上没有冲突,团队也没有手动解决任何冲突,所以我认为它是由冲突听众处理的。
有没有人知道可能导致空引用异常的原因是什么?
编辑:这是冲突侦听器的代码。除了名为UtcTimestamp
的字段外,它会检查两个版本是否相同。如果是,则使用最新版本解析。
if (conflictedDocs.Length < 2)
{
// This really, really shouldn't happen
resolvedDocument = null;
return false;
}
string previousDocument = string.Empty;
int counter = 0;
foreach (var conflictedDoc in conflictedDocs)
{
// We don't want the comparison of document versions to look at a property called UtcTimestamp
conflictedDoc.DataAsJson.Remove("UtcTimestamp");
var alteredConflictedDocString = conflictedDoc.DataAsJson.ToString();
if (counter > 0)
{
if (previousDocument != alteredConflictedDocString)
{
resolvedDocument = null;
return false;
}
}
previousDocument = alteredConflictedDocString;
counter++;
}
resolvedDocument = conflictedDocs.OrderByDescending(x => x.LastModified).First();
ConflictHelper.RemoveBadMetadata(resolvedDocument);
return true;
ConflictHelper.RemoveBadMetadata()执行此操作:
if (documentToResolveWith.Metadata.ContainsKey("@id"))
{
documentToResolveWith.Metadata.Remove("@id");
}
if (documentToResolveWith.Metadata.ContainsKey("@etag"))
{
documentToResolveWith.Metadata.Remove("@etag");
}
if (documentToResolveWith.Metadata.ContainsKey("Raven-Replication-Conflict-Document"))
{
documentToResolveWith.Metadata.Remove("Raven-Replication-Conflict-Document");
}