乌鸦查询有时只有效

Raven query only works sometimes

我们一直遇到以下查询 raven 数据库的方法有效的问题,但只有大约 90% 的时间

 member.UserId = userService.GivenUsernameGetUserId(command.EmailAddress.ToLower());

为了解决这个问题,我做了这个丑陋的 hack 解决方法,它似乎确实解决了这个问题:

member.UserId = userService.GivenUsernameGetUserId(command.EmailAddress.ToLower());
System.Threading.Thread.Sleep(1000);
if (member.UserId.IsNullOrEmpty())
{
    logger.Error("the userid was not loaded in time");
    for (int i = 0; i < 5; i++)
    {                          
        member.UserId = userService.GivenUsernameGetUserId(command.EmailAddress.ToLower());
        System.Threading.Thread.Sleep(1000);
        if (member.UserId.IsNotNullOrEmpty())
        {
            logger.Info("The userid was retrieved in a loop after some delay ");
            break;
        }
    }
    if (member.UserId.IsNullOrEmpty())
    {
        logger.Error("a loop of 5 cycles was run trying to retrieve the userId but couldn't get it.");
    }
}

谁能看出为什么它有时只能检索正确的数据,是否有更优雅的解决方案来确保它一直尝试直到检索到数据?我在想是否有一些基本的超时设置可以在 web.config 或其他东西中设置?

问题可能是过时的索引:用户是最近创建的,索引还没有机会更新。 (通常这需要几毫秒,但在大型数据库上可能需要更长的时间。)

您可以在此处执行 3 项操作来解决您的问题:

  • 选项 1:根据电子邮件地址创建用户 ID。那么你根本不必弄乱索引。
  • 选项 2:您可以保留用户 ID as-is,但等待 non-stale 个索引。
  • 选项 3:创建用户时,等待索引更新。

我将在下面描述每个选项:


选项 1:

创建您的用户 ID well-known,这样您就根本不需要用户索引了。

假设你的对象叫做用户。当您注册用户时,您的代码将如下所示:

public void RegisterUser(string emailAddress)
{
    var user = new User
    {
        UserName = emailAddress,
        ...
    };

    // Give the User a well-known ID, so that we don't have to mess with indexes later.
    user.Id = "Users/" + emailAddress;

    ravenSession.Store(user);
}

如果你这样做了,你就根本不用弄乱索引了。当需要加载您的用户时:

public string GivenUsernameGetUserId(string userName)
{
   // Look ma, no query needed.
   return "Users/" + userName;

   // Or, need to return the User itself? You can use .Load, which will never be stale.
   // return ravenSession.Load<User>("Users/" + userName);
}

这确实是您的最佳选择,您永远不必处理索引,因此,您永远不必处理过时的数据。


选项 2

选项 2 是使用 .WaitForNonStaleResults。它在返回结果之前等待索引变为 up-to-date。

public string GivenUsernameGetUserId(string userName)
{
    // Use .WaitForNonStaleResultsAsOfNow()
    return ravenSession.Query<User>()
      .Customize(x => x.WaitForNonStaleResultsAsOfNow())
      .Where(u => u.UserName == userName)
      .Select(u => u.Id)
      .FirstOrDefault();
}

选项 3

选项 3 是在 保存 您的用户时等待索引更新。

这需要 Raven 3.5 或更高版本。

public void RegisterUser(string userName)
{
    ravenSession.Advanced.WaitForIndexesAfterSaveChanges(timeout: TimeSpan.FromSeconds(30));
    var user = new User {...};
    ravenSession.Store(user);
    ravenSession.SaveChanges(); // This won't return until the User is stored *AND* the indexes are updated.
};

就个人而言,我建议为您的用户使用#1: well-known ID。此外,即使您实施其他解决方案,我也推荐#3:SaveChanges 将在返回之前等待索引更新。这将减少过时索引的意外情况,因此我通常推荐它。

我正在使用 Raven DB 3.5 并使用提到的 选项 3 这确实有效,但我在使用这种方法时遇到了问题: 在特定用例中,此操作大约需要 60 秒才能完成。 我不建议普遍使用 WaitForIndexesAfterSaveChanges(),因为它显然会导致巨大的性能问题。 相反,我会使用 WaitForNonStaleResultsAsOfNow().

配置查询