Posts tagged ‘ajax’

AjaxTask – a rails plugin for managing background tasks

SOAP, Background Tasks, and AJAX

Recently in Rails I’ve been interacting with various SOAP services and running them in the background with Workling. I needed to relay the SOAP response to the client’s web browser, so I decided to use AJAX to poll the status of my background tasks.

This is great if you have < 30 second background tasks running, but don't want to block a user (and a request).

The Solution

I created a Rails plugin, called AjaxTask, that has two components:

  • Methods to use in your controller to define a task handler and create tasks
  • Javascript library to manage the AJAX between the browser and the handler.

GitHub Link: http://github.com/chrismoos/ajaxtask

In a nutshell, the client initiates a task, the handler responds with a task ID, and the client polls at a user defined interval until the task has finished, or has an error.

The plugin takes the pain out of implementing the handler, as well as the Javascript. All you have to do is run code for your task, and periodically update the status.

I am using Workling to run my background tasks, as well as maintain the status using Workling’s return store.

Okay, enough with the intro, here is the example.

Example

Controller/Routes

The first thing to do is define the handler. This instructs the AjaxTask plugin to create a handler that will respond to ajax requests, as well as dispatch to your actual tasks. The only parameter to ajaxtask_handler is a symbol, which MUST be identical to a named route. This is how a URL gets from Rails to the plugin.

routes.rb:

map.ajaxtask_demo '/ajaxtask/handler/:task', :controller => :demo, :action => :ajaxtask_demo

demo_controller.rb:

ajaxtask_handler :ajaxtask_demo

Now we will define a task:

demo_controller.rb:

ajaxtask :mytask

This tells the plugin to respond to a task named mytask.

By doing this, we must implement two methods in our controller.

mytask_start is called when a browser starts a new task. You should probably fire off your background task in this method.

mytask_start should return a unique ID for the task. By using Workling and calling .async, a unique ID is returned.

def mytask_start
    return MyWorklingWorker.async_mytask
end
 
def mytask_status(uid)
    Workling.return.get(uid)
end

The Worker

The worker is the meat of our background task. In this we will do something that might take a while, and also update the status.

my_workling_worker.rb:

class MyWorklingWorker < Workling::Base
  def mytask(options)
    Workling.return.set(options[:uid], {:pending => 'i am just starting...wait up!'})
    begin
      # your long running task goes here
			sleep 10
    rescue => e
      Workling.return.set(options[:uid], {:error => e.to_s})
      return
    end
    Workling.return.set(options[:uid], {:done => 'i finished!})
  end
end

The important things to note here are what we set the return to. AjaxTask recognizes the following:

  • :error
  • :pending
  • :done

They should be pretty self explanatory. Now let’s see what the client side looks like.

The Client

For the client, we will be interacting with the AjaxTask javascript library. Make sure you copy the ajaxtask.js file to your javascripts directory, and include it in your page. The following will copy the javascript for you:

cd vendor/plugins/ajaxtask
rake ajax_task_js

Here is an example of what an HTML page that uses AjaxTask:

<html>
<head>
	<%= javascript_include_tag 'ajaxtask.js' %>
</head>
<body>
<script>
function mytaskHandler() {
	$(this).bind('onTaskError', onTaskError);
	$(this).bind('onTaskFinished', onTaskFinished);
	$(this).bind('onTaskPending', onTaskPending);
 
	function onTaskError(event, error) {
		alert('error: ' + error);
	}
 
	function onTaskPending(event, data) {
		alert("pending: " + data);
	}
 
	function onTaskFinished(event, data) {
		alert("finished: " + data);
	}
}
 
$(document).ready(function() {	
	var myTask = new AjaxTask({
		url: "<%= ajaxtask_demo_url :task => :mytask %>",
		handler: new mytaskHandler(),
		taskStatusDiv: $("#taskStatus"),
		taskStatusLoadingMsg: 'Please wait while my task runs...',
		taskStatusLoadingImg: '/images/smallactivity.gif',
		taskStatusErrorMsg: 'Oops...something bad happened.'
	});
	myTask.start();
});
</script>
<div id="taskStatus"></div>
 
</body>
</html>

Looking at the above client code, you can see how easy it is to present a background task’s processing to a user.

That does it for now, I’ll try to document and post more soon abou AjaxTask.

Building an Erlang chat server with Comet – Part 3

You can see a live demo of the following tutorial here.

Overview

In the last part, we implemented the first version of our chat server. Now that the framework is down, we can start adding some more features. You can find the source for this tutorial here

In this part, we will add the following features:

  • Rate Limiting for Messages
  • Admin Login
  • Kick/Ban users
  • Limiting connections per host

Rate Limiting

This feature will *help* in stopping people from spamming the chat room. It isn’t very complex, but it will give you the idea of what rate limiting can do. The algorithm for rate limiting is very simple, if a user sends too many messages in a certain interval, stop them from sending. At the top of chat_room.erl I’ve added the following:

Continue reading ‘Building an Erlang chat server with Comet – Part 3’ »

Building an Erlang chat server with Comet – Part 2

You can see a live demo of the following tutorial at chat.tech9computers.com

Getting into the code

In the previous part, I introduced the chat system and how it should work. Now we are going to write the chat_postoffice, chat_mailbox, chat_room, and chat_web modules. Before you read download the source for this tutorial here. and dedicate about 20 minutes to read through this tutorial, because it’s kind of long (sorry).

Setting up the project

When you look at the source, take a look at the structure of the files and folders. There is a makefile to help you build and run the project. To run the server, just do the following:

$ cd erl_chat
$ make erl_chat

This will compile all the code, and start the OTP application. The web server runs on port 8000.

The Mailbox Process

Before we set up the post office, let’s define how a mailbox will work. First, it will run in its own process and keep a list of messages. Essentially it is just a loop, that accepts the following messages:

Continue reading ‘Building an Erlang chat server with Comet – Part 2’ »

Building an Erlang chat server with Comet – Part 1

Introduction

Comet is a technique to stream data, or “push” events to the web browser, instead of making the client poll the server every few seconds. This lets the client receive near real-time updates. If you want to read more about Comet, check out the article on Wikipedia, more specifically, the section about Ajax with long polling, as this is what our server will implement.

I chose web based chat because it is a great “hello world” for learning how Comet works, and I really enjoy programming chat related stuff (see my very old implementation of GameRanger)

Chat Architecture

Before we get into any code, we have to talk about how the overall chat system works. Here are a few specifications.

  • Erlang is going to handle all server-side tasks.
  • Mochiweb will be used to serve the browsers.
  • There will be only one (global) chat room.
  • When a user sends a message, all others in the room will see it.

Okay, that should do it for now. That is the very basic outline of what the chat system needs to do. Now let’s talk about the server.

Server Overview

The server will use Erlang’s OTP feature to make sure that all of our services remain running and are monitored.

We are going to have the following logical services managed by OTP:

  • chat_room
  • chat_postoffice
  • chat_web

The other modules are:

  • chat_mailbox – handles mailbox processing
  • chat_util – helper functions for the application
  • chat_sup – supervisor
  • chat_server – the chat_server application

chat_room

This module will be used to maintain the state of our chat room, and allow us to implement any “chat_room” logic, such as join/leave, sending messages, etc,.

chat_postoffice

This module is very important, it will hold all the mailboxes for each user in the chat room. Whenever we want to notify a user of something, we will send a message to the “post office”. The post office will then relay the message to an individual user’s mailbox. After the message has arrived in a user’s mailbox, the mailbox may notify our web server, and the web server can notify the client’s web browser. (I know, that’s a lot handle, but don’t worry, it will be explained).

chat_web

Finally, the chat_web module is what the web browsers will be talking to, this is the front-end of the chat system. The web module will handle the basic tasks, such as joining the chat room, sending messages, and of course, receiving messages.

Implementing chat_mailbox

In Part 2, we will implement the chat_mailbox module for our chat server. (Source code will be included).