RESTful Tuplespaces
Jack Park once wondered about the possibility of creating a RESTful tuplespace protocol. At the time, my answer was not very well considered. Recently I've thought about it in much greater depth and have concluded that it probably is possible, though not for the faint of heart (I'll consider whether it should be done in another post). Much of the complexity in my strawman solution comes from three sources: the need to make POST operations idempotent; my desire to support asynchronous notifications to clients which may be transiently connected to the network; and an attempt to deal gracefully with what I call the "lost tuple" problem in destructive read operations.
To illustrate, I'll walk through a possible implementation of an asynchronous extract operation (corresponding to take() in JavaSpaces).
First, the client needs to discover the resource associated with a named space, causing the space to be created if it doesn't already exist. This operation must use the POST verb because server state may be altered.
to which the server responds with either a 200 OK or 201 CREATED status code and a Location header with the URI of the space.
POST /spacecollection?spacename=myspace HTTP/1.1
This operation can be repeated without causing harm, so no special measures need to be taken to make it idempotent. Since a space is modeled as a resource, it can be fetched via GET and should return some useful representation (exactly what representations of various resources should be is beyond the scope of this example).HTTP/1.1 201 CREATED
Location: http://myserver.com/myspace
The next client operation is not inherently harmless, so we will need to use some technique to associate a message id with the request.
To which the server responds with a globally unique message id:
POST /myspace?op=getmessageid HTTP/1.1
HTTP/1.1 201 CREATED
Location: http://myserver.com/myspace?messageid=1234567890
Now that we have a message id, we can POST a template to the space. This is conceptually similar to subscribing to notification for an event. Note that for security reasons, the URI provided by the subscriber to receive notifications should be hard to guess and should not be used more than once.
The server will respond with a URI representing the stored template (subscription):
POST /myspace?messageid=1234567890&op=take HTTP/1.1
Subscriber: http://myclient.com/notifications?0987654321
<template in message body>
The template is modeled as a resource and may be fetched with a GET, or removed with DELETE by a properly authorized client.
HTTP/1.1 201 CREATED
Location: http://myserver.com/myspace?template=0987654321
Time passes...and a tuple matching the template becomes available. The server uses the given subscriber resource to notify the client of the event.
This is quite safe for the client, because no information is conveyed in the server's POST. The meaning of the notification has been privately agreed upon in advance.
POST /notifications?0987654321 HTTP/1.1
HTTP/1.1 200 OK
This is where things get especially tricky. First, it is possible (in fact, likely) that more than one template (subscription) will be fulfilled by the incoming tuple. The server will want to notify all subscribers and allow them to compete for the available tuple, in order to reduce the possibility that the tuple will be left undelivered and therefore in limbo (the "lost tuple" problem). Also, in the real world it is likely that not all clients will be permanently and reliably connected to the network, and therefore the server may fail to deliver one or more notifications (the server should use some application-defined number of retries and an exponential back-off strategy). To cope with this, it must be possible for a client to check on the status of a template/subcription. So...after either receiving a notification, OR being reconnected to the network, a client should perform a GET on its subscription resource:
If the template has been fulfilled, the server will respond with the location of the matching tuple (the tuple will already have been removed from the space, and assigned a new, temporary URI).
GET /myspace?template=0987654321 HTTP/1.1
Now the client can attempt to retrieve the tuple. Since there is no way to do an atomic GET+DELETE, we'll have to use a POST operation.
HTTP/1.1 307 Temporary Redirect
Location: http://myserver.com/myspace?tuple=AB12678C
The first client to POST to this URI will cause both the tuple and the template to be permanently removed from the space (subsequent GETs on the resources will return 410 Gone). The server will deliver the tuple in the body of the response.
POST /myspace?tuple=AB12678C&template=0987654321 HTTP/1.1
If no client "claims" the tuple within an application-defined period, the server will return the tuple to the space and mark the temporary URI as Gone. This is the only way I can conceive to prevent the lost tuple problem.
HTTP/1.1 200 OK
<tuple in message body>
Clearly, this isn't as simple as sending a few SOAP messages back and forth over some reliable message service. Since this post is already too long, I'll have to save any detailed commentary for another time. Although this blog doesn't have a comment system (yet), please email me with any comments, and I'll post a summary of any feedback I receive.
0 Comments:
Post a Comment
<< Home