akostadinov
akostadinov

Reputation: 18594

How to get server time with mongoid 3.x?

Using MongoDB to schedule resource reservations. To be sure a broken client will not break the system I'd like to get server time and base queries on it.

I think that's possible with server side javascript but this is not directly supported by mongoid gem and doesn't work because of db user permissions it seems. I'm doing:

  time_now = MongoModels::User.collection.database.session.cluster.with_primary do
    MongoModels::User.collection.database.command(eval: """
      function() {.
        var now=new Date()
        return now.toISOString()
      """
    )
  end

I'm getting:

failed with error 13: "not authorized on cucushift to execute command { eval:
...

Another approach I thought would work without using javascript is getting server status. It should contain local time. But I can't find a way to get server status with mongoid.

If anybody knows how to get server status or knows another way to get server local time. Or knows how to craft my query so that it compares with server time instead of client machine time, then that would be awesome. Thank you!

update: it seems I'm also disallowed to do serverStatus:

MongoModels::User.collection.database.command(serverStatus: 1)

failed with error 13: "not authorized on cucushift to execute command { serverStatus: 1 }"

This is strange IMO because it is not listed as admin only. Doing listCommands I see:

"serverStatus"=>
    {"help"=>"returns lots of administrative server statistics",
     "slaveOk"=>true,
     "adminOnly"=>false}

Upvotes: 0

Views: 222

Answers (2)

Jeff S.
Jeff S.

Reputation: 165

For a more direct approach with Mongoid 3, check server time with this. It does not require you to query a collection:

Mongoid::Sessions.default.command(ismaster: 1)["localTime"]

For Mongoid 5, use this command to check the server time:

Mongoid::Clients::Factory.default.command(ismaster: 1).documents[0]["localTime"]

Upvotes: 2

akostadinov
akostadinov

Reputation: 18594

I found out the best way - allowing user to request server status. That's because the serverStatus command looks to be secure and is claimed to not affect mongodb server performance. To enable the account to get server status first I follow this serverfault question.

Then in ruby I do the above mentioned:

server_status = MongoModels::User.collection.database.command(serverStatus: 1)

Then I'm getting server time with:

[2] pry(#<CucuShift::MongoUserPoolQuery>)> server_status["localTime"]
=> 2014-10-29 09:44:55 UTC
[3] pry(#<CucuShift::MongoUserPoolQuery>)> server_status["localTime"] + 3600
=> 2014-10-29 10:44:55 UTC
[4] pry(#<CucuShift::MongoUserPoolQuery>)> server_status["localTime"].class
=> Time

I hope this helps somebody in the future.

btw I think it is also possible to get server time by saving a document and setting one of the fields to server current time. There are a couple of ways - see Is there any Equivalent of NOW() in MongoDB. Then read the doc and get server time at point of record insertion. But I think that is more heavyweight.

Upvotes: 0

Related Questions