Forumwarz and RJS: A Love/Hate Affair

Loading...

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

0 comments

Post a comment

    Post a comment
    Embed Video
    Edit your comment Cancel

    Favorites, Groups & Events

    Forumwarz and RJS: A Love/Hate Affair - Presentation Transcript

    1. Forumwarz and RJS A love/hate affair
    2. An internet-based game about the internet
    3. LOL WHUT?
    4. The Internet is a wonderful, magical place!
    5. But it’s also terrible.
    6. Very, very terrible.
    7. John Gabriel’s Greater Internet Fuckwad Theory
    8. Exhibit A
    9. Have you heard of it? • One of the most popular forums in the world • Almost all its users are anonymous • Unfortunately, it’s hilarious.
    10. The anonymity of the Internet means you can be anything...
    11. You can be another ethnicity!
    12. You can be another species!
    13. You can even be beautiful!
    14. (Even if you’re not.)
    15. Are you going to explain what forumwarz is, or just show us hackneyed image macros all night?
    16. Role-Play an Internet User! Camwhore Emo Kid Troll
    17. Role-Play an Internet User! • Each player class features unique abilities and attacks • Many different ways to play • A detailed story line ties it all together
    18. An interface heavy in RJS (please endure this short demo)
    19. Let’s get technical
    20. Forumwarz Technology
    21. Some of our stats • ~30,000 user accounts since we launched one month ago • 2 million dynamic requests per day (25-55 req/s) • Static requests (images, stylesheets, js) are infrequent, since they’re set to expire in the far future • About 25GB of bandwidth per day
    22. Deployment • Single server: 3.0Ghz quad-core Xeon, 3GB of RAM • Nginx proxy to pack of 16 evented mongrels • Modest-sized memcached daemon
    23. Thank you AJAX! • One reason we can handle so many requests off a single server is because they’re tiny • We try to let the request get in and out as quickly as possible • RJS makes writing Javascript ridiculously simple
    24. why we rjs
    25. A simple example Example View #battle_log There's a large monster in front of you. = link_to_remote \"Attack Monster!\", :action => 'attack' Example Controller def attack @monster = Monster.find(session[:current_monster_id]) @player = Player.find(session[:current_player_id]) @player.attack(@monster) update_page_tag do |page| page.insert_html :top, 'battle_log', :partial => 'attack_result' end end
    26. Pretty cool eh? • Without writing a line of javascript we’ve made a controller respond to an AJAX request • It’s fast. No need to request a full page for such a small update • It works great*
    27. * but it can haunt you
    28. Problem #1: Double Clicks • Often, people will click twice (or more!) in rapid succession • Your server gets two requests • If you’re lucky they will occur serially
    29. A Solution? • Use some javascript to prevent multiple clicks on the client side var ClickRegistry = { clicks : $H(), can_click_on : function(click_id) { return (this.clicks.get(click_id) == null) }, clicked_on : function(click_id) { this.clicks.set(click_id, true) }, done_call : function(click_id) { this.clicks.unset(click_id) } }
    30. A Solution? • Add a helper, link_once_remote def link_once_remote(name, options = {}, html_options = {}) click_id = html_options[:id] || Useful.unique_id options[:condition] = \"ClickRegistry.can_click_on('#{click_id}')\" prev_before = options[:before] options[:before] = \"ClickRegistry.clicked_on('#{click_id}')\" options[:before] << \"; #{prev_before}\" if prev_before prev_complete = options[:complete] options[:complete] = \"ClickRegistry.done_call('#{click_id}')\" options[:complete] << \"; #{prev_complete}\" if prev_complete link_to_remote(name, options, html_options) end
    31. Our Example: v.2 Example View #battle_log There's a large monster in front of you. = link_once_remote \"Attack Monster!\", :action => 'attack'
    32. Surprise! It doesn’t work!
    33. Why not? • Proxies or download “accelerators” • Browser add-ons might disagree with the javascript
    34. Also, it’s client validated! • Let’s face it: You can never, ever trust client validated data • Even if the Javascript worked perfectly, people would create greasemonkey scripts or bots to exploit it • Our users have already been doing this :(
    35. Server Side Validation • It’s the Rails way • If it fails, we can choose how to deal with the invalid request • Sometimes it makes sense to just ignore a request • Other times you might want to alert the user
    36. Problem #2:Validations • ActiveRecord validations can break during concurrency • In particular, the validates_uniqueness_of validation
    37. The Uniqueness Life-Cycle select * from battle_turns where turn = 1 and user_id = 1; if no rows returned insert into battle_turns (...) else return errors collection
    38. Transactions don’t help • With default isolation levels, reads aren’t locked • Assuming you have indexed the columns in your database you will get a DB error • So much for reporting errors to the user nicely!
    39. A solution? • Could monkey patch ActiveRecord to lock the tables • That’s fine if you don’t mind slowing your database to a crawl and a ridiculous amount of deadlocks
    40. A different solution? • You can rescue the DB error, and check to see if it’s a unique constraint that’s failing • This is what we did. It works, but it ties you to a particular database def save_with_catching_duplicates(*args) begin return save_without_catching_duplicates(*args) rescue ActiveRecord::StatementInvalid => error if error.to_s.include?(\"Mysql::Error: Duplicate entry\") # Do what you want with the error. In our case we raise a # custom exception that we catch and deal with how we want end end end alias_method_chain :save, :catching_duplicates
    41. Problem #3: Animation • script.aculo.us has some awesome animation effects, and we use them often. • RJS gives you the great visual_effect helper method to do this: page.visual_effect :fade, 'toolbar' page.visual_effect :shake, 'score'
    42. When order matters • Often you’ll want to perform animation in order • RJS executes visual effects in parallel • There are two ways around this
    43. Effect Queues • You can queue together visual effects by assigning a name to a visual effect and a position in the queue. • Works great when all you are doing is animating • Does not work when you want to call custom Javascript at any point in the queue • Unfortunately we do this, in particular to deal with our toolbar
    44. page.delay page.visual_effect :fade, 'toolbar', :duration => 1.5 page.delay(1.5) do page.call 'Toolbar.maintenance' page.visual_effect :shake, 'score' end • Executes a block after a delay • If paired with :duration, you can have the block execute after a certain amount of time
    45. It’s me again! This also doesn’t work!
    46. Durations aren’t guaranteed • Your timing is at the whim of your client’s computer • Your effects can step on each other, preventing the animation from completing! • They will email you complaining that your app has “locked up”
    47. A solution? def visual_effect_with_callback_generation(name, id = false, options = {}) options.each do |key,value| if value.is_a?(Proc) js = update_page(&value) options[key] = \"function() { #{js} }\" end end visual_effect_without_callback_generation(name, id, options) end alias_method_chain :visual_effect, :callback_generation Thanks to skidooer on the SA forums for this idea!
    48. And then, in RJS page.visual_effect :fade, 'toolbar', :duration => 1.5, :afterFinish => lambda do |step2| step2.call 'Toolbar.maintenance' step2.visual_effect :shake, 'score' end • The lambda only gets executed after the visual effect has finished • Doesn’t matter if the computer takes longer than 1.5s
    49. in Conclusion
    50. Nobody’s Perfect!
    51. Nobody’s Perfect! • We love RJS despite its flaws • It really does make your life easier, most of these issues would never be a problem in a low traffic app or admin interface • The solutions we came up with are easy to implement
    52. this presentation was brought to you by
    53. this presentation was brought to you by Any questions?

    + guest06ed72guest06ed72, 2 years ago

    custom

    910 views, 0 favs, 0 embeds more stats

    A presentation given at TSOT rails project night ab more

    More info about this document

    © All Rights Reserved

    Go to text version

    • Total Views 910
      • 910 on SlideShare
      • 0 from embeds
    • Comments 0
    • Favorites 0
    • Downloads 13
    Most viewed embeds

    more

    All embeds

    less

    Flagged as inappropriate Flag as inappropriate
    Flag as inappropriate

    Select your reason for flagging this presentation as inappropriate. If needed, use the feedback form to let us know more details.

    Cancel
    File a copyright complaint
    Having problems? Go to our helpdesk?

    Categories