Alright, this is a design question more than anything. I am making a text based game using Ruby on Rails 3, and I'm not sure the best way to implement what I want to do. In the game, the user gets a bunch of goblins, and can tell those goblins what to do. One of the available actions is attack, which as you can assume, means your tribe attacks something else, whether it be an opposing tribe, or a NPC settlement.
If you choose to attack an opposing tribe, then your goblins go off to attack. There is a set point when the battle will commence, (let's say, 10 minutes in the future). Here's the question, what's the best way to implement running the simulation for the battle in exactly 10 (or X) minutes in the future? Because if the simulation is run too soon or too late, then the entire outcome of the battle could be changed by what the opponent does.
(I know it's a little vague, but for those of you who have played Ogame, entire battle outcomes can change if the simulation is run a second too soon or late.)
I was looking at ways to implement having something run at X time in the future (this episode, and the two previous), but it doesn't seem to be tuned toward something that needs to be run precisely at time X. I also looked in to Ruby timers, but there doesn't seem to be a consistent one, like there is in java, nor do they automatically make the data persistent. I was hoping for low coupling too, perhaps using the observer pattern.
So there you have it. If I send my attack, or want to do anything at exactly time X in the future, what's the best way to do this in Ruby on Rails?
Simple answer: Don't
You should save the time (now+10 minutes) in a database and then run a cronjob every minute (or whatever you prefer). This should then evaluate all fights that should be fought at that time.
For best practices on this behaviour see A cron job for rails: best practices?
You could also add a check if a fight can be fought on every request you get. This way you'll get a little bit more randomness when the fight will start exactly and depending on the traffic of your site, this could be like every second. Remember to start a thread to evaluate the fight, depending on the amount of your calculations. Otherwise some users can experience massive lags.
The typical thing to do if you want some event to happen in the future with ruby on rails is to use cron to fire externally (as simon suggested) or use the delayed_job gem and set a job for the future. You can also use rufus-scheduler gem like this:
scheduler.in '10m' do
puts "something happening 10 minutes from now"
end
Related
Okay, so my User models are able to 'spend' points to give karma (arbitrary points) to other users - each time the User gives a point, their karma_amount is decremented, as you might expect. I'd been originally planning on making it so a user couldn't give karma to another user more than once, but then I thought that it would be cooler to have a finite stock of points that replenishes, by say 1 point every two days.
I'm not quite sure how to accomplish this though - if it was a Ruby script on my machine, sure, but does anybody have any tips having tried something similar in Rails?
My other concern is that if every user has a ticking clock on the live app that'll slow the whole thing down. I guess what I'm asking in a nutshell is: what is the 'Rails-y' way of doing this? Naturally I'd rather find something robust or elegant than just hacking away.
Thanks very much.
You want something that run every period of time (two hours in your example). The operation itself (replenish_karma) could be a simple controller action (be sure to restrict its access, still), then you just need to be sure to call it on a regular basis.
A very simple way could be a simple cron on the server that would initiate a call to that specific route. If you want something inside your rails application, you may want to take a look at background task libs such as delayed_job or resque.
I want to make a game in rails (not with flash, just html). Every action should take some time to execute. For example, user can send an action to his hero "go learn ". It should lasts for 10 minutes. What's the best way to implement it?
I want to store player tasks in my database, but how should I do their execution?
1 way: when user log in or do something, check his tasks and look for finished ones.
2 way: check tasks on my app every X seconds and look for finished ones.
3 way: use something like Delayed Job gem. Do you think its good for my problem?
You could use delayed job, to run the task.With that there is problem that you will have tomanage "many" workers when there is extra load on the site, but its not that bad either, its doable as long as it "runs" every task exactly after 10 minutes.
You can still use a combined approach using 1 & 2 which would generally work.
I am now researching for a solution to perform similar task and just recently came across a railscasts episode that I found worthy of noting down.
Using custom deamons (and a number of other interesting topics) found here.
P.S.
I see that you have asked this question a while back. Could you please share how you ended up implementing your solution.
Cheers
How would you update attributes in your database based on the time of day or what day it is. I have three attributes energy, hunger, and happiness that I want to decrease by ten every hour but I don't quite know how to go about doing this. I know there are timestamps in the database but I don't really know how to use them. Also I want to change the players skills every day based on their job. So if you have this job, add 2 to intelligence every day. But I don't know how to add that 2 every day. I would love it if anyone could give me help on this problem. I would greatly appreciate it.
A couple of options:
cronjob: You could setup your cronjob to access the database directly through a SQL script (probably the simplest solution out of all in terms of setup) or go through your rails application first (e.g. in case you need to run additional business logic before updating the database - you mentioned something about updating the database based on the user job). See this post for the latter approach.
Background task: Take a look at Starling/Workling or Backgroundrb. You can use either of these to run a background task that could update your database at regular intervals.
There are two common but fundamentally different ways of achieving this:
During each request, simulate the amount of time which has passed since the last request. If a user makes two requests three hours apart, simulate three hours of time passing by subtracting 30 happiness (10/hour times 3 hours) all at once. This is less resource intensive, but requires a little more thinking on your part. It's not difficult for something as simple as "lower a value by 10 every hour", but more complex interactions are more difficult to model.
Run a cron job which invokes an action in your program every hour, on the hour, to deduct 10 happiness from each account. This is easier conceptually, but involves a lot of overhead if you have many users, especially when some of them are idle for long periods.
I am attempting to create a web-based game in Ruby on Rails. I have a model named 'Game', which has a datetime in the database entry that corresponds to a time that I would like the server to call the Game model's update_game function. Depending on the game's settings, this could be every 30 seconds to every 12 hours.
Ruby on Rails only seems to work when it receives an HTTP request; is there a slick way to get my game to update on a periodic basis independent of HTTP requests?
I'd look into delayed_job for this. When the game starts, you can create a delayed_job for the first update, and every run after that can add a new job at the correct interval until it's done.
I'd do lots of testing though ;) - you don't want to let the jobs get away from you.
Rails itself doesn't do this; cron does this. Ruby does, however, have a gem named Whenever to make easier the declaration and deployment of new cron jobs.
However, if you are really going to expect a large amount of games to reliably update every 30 seconds, you may want to take a different approach if updating a game would take any significant amount of time. Perhaps once the game is accessed, the game could run the update as many times as necessary (e.g. if 3 minutes had passed and the interval is 30 seconds, run 6 updates once requested). This may or may not be a good option for your setup, however, so figure out which method is more viable for your purposes.
Look into background processing options and possibly cron.
I like the gem 'rufus-scheduler' which works within Rails, though I'm not sure you can programmatically add more tasks to it.
Like with browser games. User constructs building, and a timer is set for a specific date/time to finish the construction and spawn the building.
I imagined having something like a deamon, but how would that work? To me it seems that spinning + polling is not the way to go. I looked at async_observer, but is that a good fit for something like this?
If you only need the event to be visible to the owning player, then the model can report its updated status on demand and we're done, move along, there's nothing to see here.
If, on the other hand, it needs to be visible to anyone from the time of its scheduled creation, then the problem is a little more interesting.
I'd say you need two things. A queue into which you can put timed events (a database table would do nicely) and a background process, either running continuously or restarted frequently, that pulls events scheduled to occur since the last execution (or those that are imminent, I suppose) and actions them.
Looking at the list of options on the Rails wiki, it appears that there is no One True Solution yet. Let's hope that one of them fits the bill.
I just did exactly this thing for a PBBG I'm working on (Big Villain, you can see the work in progress at MadGamesLab.com). Anyway, I went with a commands table where user commands each generated exactly one entry and an events table with one or more entries per command (linking back to the command). A secondary daemon run using script/runner to get it started polls the event table periodically and runs events whose time has passed.
So far it seems to work quite well, unless I see some problem when I throw large number of users at it, I'm not planning to change it.
To a certian extent it depends on how much logic is on your front end, and how much is in your model. If you know how much time will elapse before something happens you can keep most of the logic on the front end.
I would use your model to determin the state of things, and on a paticular request you can check to see if it is built or not. I don't see why you would need a background worker for this.
I would use AJAX to start a timer (see Periodical Executor) for updating your UI. On the model side, just keep track of the created_at column for your building and only allow it to be used if its construction time has elapsed. That way you don't have to take a trip to your db every few seconds to see if your building is done.