Hi TK,

we had the same problem with ClientResource called within request handling
on an JSE 2.1-snapshot server. Especially, when calls were not answered
correctly (remote server not started, network timeouts etc.) the calling
server soon run out of threads and became unresponsive.

I think that the basic problem is that in this area the restlet framework
relies on the garbage collector of the jvm. It doesn't matter whether your
variables are local or private members, when they go out of scope there is
no guarantee that finalize is called on them any time soon (sometimes it
would be really nice to have destructors in Java). Tweaking the jvm with max
mem and other settings might lead to the gc never being called before you
run out of threads.

As stated elsewhere in this forum a basic solution could be to always call
exhaust and release on a representation after using it (samples in Scala):

val representation = response.getEntity
if (null != representation) {
  try {
     // do something with it
  } finally {
    representation.exhaust
    representation.release
  }
}

To not clutter our code with this we adopted the "Disposable Pattern" for
Scala:

    trait Disposable[S] {
        def dispose
    }

    trait ContextType[T]

    def forceContextType[T]: ContextType[T] = null

    private def use[S <% Disposable[S], T: ContextType](what: S)(block: S =>
T): T = {
        try {
            block(what)
        } finally {
            what.dispose
        }
    }

    def disposable[S <% Disposable[S], T: ContextType](what: S): S @cps[T] =
shift(use[S, T](what))

    def using[T](block: => T @cps[T]): T = reset { block }

    // implicit conversions

    implicit def d[S](what: S { def exhaust(): Long; def release() }):
Disposable[S] = {
        new Disposable[S] {
            def dispose() = {
                what.exhaust
                what.release
            }
        }
    }

This allows cleaner code (many details omitted):

val data = using {
  implicit val _ = forceContextType[Json.JObject]
  val client = ApplicationResource(uri)
  val representation = disposable(client.get(MediaType.APPLICATION_JSON))
  Json.parse(new
InputStreamReader(representation.getStream)).get("response").asObject.get("data").asObject
}

With "using" and "disposable" the compiler ensures that in either case
(success or failure) the representation is exhausted and released. In case
of failure the exception is handled elsewhere.

Now this is Scala and doesn't help much in a pure Java environment. I think
it would be great if this were made part of Restlet, but I'm sure it
wouldn't be easy.

Guido Schmidt.

-- 
View this message in context: 
http://restlet-discuss.1400322.n2.nabble.com/Threads-never-close-for-ClientResource-tp5164847p5947044.html
Sent from the Restlet Discuss mailing list archive at Nabble.com.

------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=2699549

Reply via email to