Objects>Queues
Introduction Installation Beginning Admin Quick Ref FTP Server SMTP Server Database Security
Statements Objects String Parsing Events Queues Samples Special names Error Handling Accessories   Back
Caravan Business Server>Help>Objects>Queues
Syntax <caravan>
      queue objectname(name,[type]);// type is optional
            Where name and type are either strings or variable data.
</caravan>
    
Text   
A Queues is basically a list of objects which can be accessed in the same order in which they are put. This is called a FIFO, for first in first out.

In caravan an object of type queue is available which is persistent (meaning it will not vanish if server is shut down). The queues are used to schedule tasks that need to be done sequentially. For example, take the situation where a lot of messages have to be send from one server to many other sites. The task that creates the message usually does not want to wait till the message is dispatched to the destination. Dispatching the message can be done in a separate thread. This thread can be made be made to poll for any new messages  and send them one by one. But in case there are no messages it still needs to poll for new messages. This is an unnecessary wastage of CPU resources. The queue mechanism along with the concept of event handler provides an elegant solution for such situations.

By creating a queue and the corresponding event handler it is possible to dispatch tasks that are sporadic. Whenever an item is inserted into the queue, the corresponding event handler is triggered. The event handler is resumed and starts dispatching the queued task. (Entering an item in queue is akin to creating an event).

The best thing is that the what is inserted into the the queue and how the task is handled is totally programmable.

A Queue is identified by its 'name' and optionally a 'type'. This is because usually a particular task is handled depending on some information that distinguishes from other tasks-- each message is distinguished by the destination address though the logic of the task is the same.

A queue object can be used to create the queues of any name and type. Also a queue object can be used to access an existing queue and manipulate and view its status.

The queue object is used for creating, viewing and manipulating the queues
  
    
Sample <caravan>
Examples declaring a queue object x:

      1.queue x(myq,yahoo); // the queue name is myq and type is yahoo

      2.queue x(y(name),y(typ));// the name and type are variable

      3.queue x(myq);// the name is qname and applicable to all types

      4.queue x(myq,*);// the name is qname and applicable to all types
      
Example
      queue x(smtp)
      queue x(smtp,yahoo.com)
</caravan>


We  will illustrate the use of queue and eventhandler through an example.

Assume we have server recieving information from post operations coming from users
and other servers. The job of the server is to store this data in folders depending
on the catagory information in the form. The form consists of 'message', 'catagory'' and
'forwardto' .

The message is  some file of unknown size, which needs to be saved
to some folder depending on the 'catagory' and the 'forwardto' are a list of servers
which should also be updated with this data.

We have a data base called messages which contain three tables

1. files:
    Holds the data on the local serrver. This is updated every time a form is
    accepted by our server.
2. catagories: holds category and folder information
    Contains two fields
    catagory : a string to denote a the category -- say news, graphics, messages
    folders : a list of folders in which this catagory has to be stored
3. servers:  Contains server information.
    servername, and ipaddress and port


The task is to accept the form, update our table 'messages.files', save the message into its respective
folder and forward it to the indicated servers.

We can write the code to in such a way that all the above are done in one process. The drawback
is that each thread will take an undefined amount of time and if there are many simultaneous requests
everything will slow down to a crawl. The code for doing it this way is given below.

Code for 'accept_message.html'

<caravan>
// this code is executed when a form is posted to caravan.

// first put the data into the 'files' table
table store=messages.files
store(message)=form(message)
store(category)=form(category)
store(forwardto)=form(forwardto)
store(insert)

// Now save the message in our folder

table cat=messages.categories

select from cat where category={category}
if cat(selected)> "0" ;// yes we have identified soe categories
  loop cloop (cat(selected)) ;// there can be multiple folders in which we have to save
    folder df=cat(folder)
    df(file)=form(message)
    cat(nextrecord)
  repeat cloop
endif

// now send to other servers

loop dloop (form(forwardto(00)))
  table servers=messages.servers
  var sql
  sql(servname)=form(forwardto(dloop(count)))
  select from servers where servername={servname}
  if servers(selected)="1";// ideally only there should only be one entry per server
     form myform
     myform(_server)=servers(ipaddress)
     myform(_port)=server(port)
     myform(_url)="accept_message.html"
     myform(message)=form(message)
     myform(category)=form(category)
     myform(post)
  endif
repeat dloop

// now send reply to the client who posted

"OK : recvd message"
</caravan>


The above code is a simplified form of a communication process. We can see that each part of the
code can take much time to complete and the sender of the original form has to wait an undefined amount of time
to get the response 'Ok : recvd message'.

Now we will split the task into three parts :

Receive data: 'accept_message.html'

<caravan>
// this code is executed when a form is posted to caravan.

// first put the data into the 'files' table
table store=messages.files
store(message)=form(message)
store(category)=form(category)
store(forwardto)=form(forwardto)
store(insert)

// Now queue the task

queue saveq("save") ;// a queue is created for saving the data into folders
saveq(item)=store(recordno)
queue sendq("send") ;// another queue is created to send the data to downstream servers
sendq(type)=store(forwardto)
sendq(item)=store(recordno)
"OK : recvd message" ;// reply ok to sender
</caravan>


In the above code all parts of the task is not completed, we have just updated our database and replied 'ok'
to sender. The other parts of the task are done by eventhandlers. We have used the queue object to create
two events which will trigger the respctive eventhandlers.

Event handler for saving the message in local file system:'save.html'

<caravan>
_eventhandler ("save");// this says that the follwing code is to be executed when a 'save' event is generated.

// there is a queue object '_event' which is already created when this eventhandler is triggered which
// is equivalent to the decaration:
// queue _event("save")

table store=messages.files
// retrieve the item
store(recordno)=_event(item) ;// now we are pointing to the record which contains the message
// rest of the code is similar to what we did before except that now we dont have the original
// object 'form' which was posted to us -- we have to get the message from our table
table cat=messages.categories
var sql
sql(category)=store(category)
select from cat where category={category}
if cat(selected)> "0" ;// yes we have identified some categories
  loop cloop (cat(selected)) ;// there can be multiple folders in which we have to save
    folder df=cat(folder)
    df(file)=store(message)
    cat(nextrecord)
  repeat cloop
endif
_event(deleteitem);// done with this item, delete it
// handler will restart with next item if any or gets suspended till another event occurs
// if no event occurs for a long time the thread dies and frees up the resources
</caravan>


For every message received the above code is executed and the message is saved to its
required folder without delaying our client. Note that by not specifying any 'type' for the
eventhandler we are ensuring that the messages are processed in the order they have landed,
in a sequential manner.

Now we need a event handler to send the messages to other servers. Here we will demostrate
a slightly different way of handling this task. Since a single message may have to go to
multiple servers we will need to send them concurrently -- else all servers may have to face
unacceptable delay.


Event handler for sending the message to a downstream server:'send.html'

<caravan>
_eventhandler(send,?);// create an instance of this eventhandler for each type
// there is a queue object '_event' which is already created when this eventhandler is triggered which
// is quivalenent to the decaration:
// queue _event("send",servername)
// the 'type' here is the servername

  table store=messages.files
// retrieve the item
  store(recordno)=_event(item) ;// now we are pointing to the record which contains the message
  table store=messages.files
  store(recordno)=_event(item)
  table servers=messages.servers
  var sql
  sql(servname)=_event(type)
  select from servers where servername={servname}
  if servers(selected)="1";// ideally only there should only be one entry per server
     form myform
     myform(_server)=servers(ipaddress)
     myform(_port)=server(port)
     myform(_url)="accept_message.html"
     myform(message)=form(message)
     myform(category)=form(category)
     myform(post)
     if _reply(error);// if there was error set a delay of 300 seconds before trying again.
       _event(wait)="300"
       goto skipdelete;// dont delete it now
     endif
  endif
  _event(deleteitem);// delete this item from 'send' queue
label skipdelete
</caravan>

The above code illustrates how caravan can use the multithreading features of the OS to speed up the response time and performance of your application. This way the message is send to one server per thread. So many threads can become active at once and finish the job much faster.
      
Properties total
name
QueueId
priority
wait
type
Item
next
delete
select
resume
Home       Back