Raven查询有时只能工作

时间:2017-01-25 13:31:47

标签: c# ravendb

我们遇到了一个问题,其中查询乌鸦数据库的以下方法有效,但只有大约90%的时间

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

为了抵消这一点,我做了这个丑陋的黑客解决方法似乎解决了这个问题:

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中设置一些基本的超时设置?

2 个答案:

答案 0 :(得分:2)

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

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

  • 选项1:根据电子邮件地址创建用户ID。然后你根本不必乱用索引。
  • 选项2:您可以按原样保留用户ID,但等待非陈旧索引。
  • 选项3:创建用户时,请等待索引更新。

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

选项1:

让您的用户ID众所周知,这样您就不必拥有用户索引了。

假设您的对象名为User。注册用户时,您的代码将如下所示:

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。它会在返回结果之前等待索引变为最新。

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:众所周知的ID。此外,即使您实现其他解决方案,我也建议使用#3:SaveChanges将在返回之前等待索引更新。这将导致陈旧索引周围的意外减少,因此我建议一般。

答案 1 :(得分:0)

我正在使用Raven DB 3.5,并使用提到的选项3 确实可以,但是使用这种方法遇到了一个问题: 在特定的用例中,此操作大约需要60秒钟才能完成。 我不建议一般使用WaitForIndexesAfterSaveChanges(),因为它显然会导致巨大的性能问题。 相反,我将使用WaitForNonStaleResultsAsOfNow()配置查询。