I have been using http-agents to grab a bunch of pages and then
process them, my initial solutions involved partitioning a sequence of
urls and then awaiting for that group before moving on.

(I'm using clojure-1.1.0 and clojure-contrib-1.1.0)

However the problem with that approach is that when one of the
responses is slow they all have to wait.  To get around that I can
loop and query each running agent with done? etc, but that is a
hassle.

I figured I'd use the :handler function instead, when the handler is
called I can deal with the response body and then fire off another
agent.  However the agent's state hasn't changed internally to ::done
yet so not all the accessors work (like status, for example).

No problem I thought just queue another action behind the initial
http-agent request.  As I am sending the actions from the same thread
they are guaranteed to run sequentially so my second action will have
access to the final agent state and then all the accessors will work,
etc.

However there is another wrinkle; both string and result call await
and you can't await in an action.

I want to do the following;

(let [agnt (http-agent "http://slashdot.org/";)]
    (send agnt
          (fn [state]
            ;; printing for demonstration but could write to file,
post to another queue, etc.
            (println  "Done:" (done? *agent*) "Status:" (status
*agent*))
            ;; the following causes an error as string calls await
which is bad in an action
            (println (string *agent*))
            state)))

This seems fairly idiomatic to me but I end up with agnt having the
"can't await in action" error.  After I redefine result and string
(the only two that await in http-agent) to be the following;

(in-ns clojure.contrib.http.agent)

(defn string
  "Returns the HTTP response body as a string, using the given
  encoding.

  If no encoding is given, uses the encoding specified in the server
  headers, or clojure.contrib.duck-streams/*default-encoding* if it is
  not specified."
  ([http-agnt]
     ;; may have to wait for Content-Encoding
     (if (not (done? http-agnt))
       (await http-agnt))

     (string http-agnt (or (.getContentEncoding
                            #^HttpURLConnection (::connection @http-
agnt))
                           duck/*default-encoding*)))

  ([http-agnt #^String encoding]
     (.toString (get-byte-buffer http-agnt) encoding)))

(defn result
  "Returns the value returned by the :handler function of the HTTP
  agent; blocks until the HTTP request is completed.  The default
  handler function returns a ByteArrayOutputStream."
  [http-agnt]
  (if (not (done? http-agnt))
    (await http-agnt))
  (::result @http-agnt))

Then everything is fine and the code above works.  Interestingly this
doesn't change the documented behaviour of result as result still
blocks until complete but now only if it needs to which means I am
free to call result in a later action.

Finally my question, is my usage of actions idiomatic and I have just
stumbled onto an unusual usage pattern for http-agent or is there some
reason that await is always called in string and result that I am
unaware of?

-- sim

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to