users@grizzly.java.net

RE: Problem with Suspend/Resume

From: Gay David (Annecy) <"Gay>
Date: Thu, 20 Jan 2011 13:40:19 +0100

Hi Alexey,

 

Interesting ... some questions if you mind :

 

* You remove all the tests regarding response.isSuspended() before suspending or resuming, is it because it's useless or not "safe" (because I see this method is not sync in the source) ?

 

* In the MyExecutor.run() method, you replace the Response.finish() by a Response.flush(), is it because it's wrong to call finish() in sync mode ?

 

* Also, you comment the response/request recycling in MyAdapter.afterService(). Again, is it because it's useless or because it's wrong ? I made some tests to call or not recycle, but it's doesn't seems to break something.

 

 

I ask myself many question also, because right now, in my server integration, the usage of the async adapter (MyAdapter) is only a decorator that is install or not on the root adapter, based on some configuration parameter. And of course this adapter call other adapters (like the Jersey GrizzlyContainer). Basically, it's more or less like that :

 

public class MyAsyncAdapter

{

         Adapter target;

         ThreadPoolExecutor executor;

         

         public MyAsyncAdpater( Adapter target )

         {

                   this.target = target;

         }

         

         public void service( Request request, Response response ) throws Exception

         {

                   response.suspend();

                   executor.execute( new MyExecutor(request,response,target) );

         }

         

         public void afterService( Request request, Response response ) throws Exception

         {

                   target.afterService( request, response );

         }

}

 

Does it seems to be ok for you ?

What if the target adapter does a recycle() on request/response or/and finsh() or other call that is not allow to do in async ?

 

Last note, we use this design, because in our server, some request takes long time (download huge file for example), and we don't want to block other users for quick request (mainly REST). At first, we just increase the selector max thread, but it takes too much memory. That's why we implements this design, by delegating the requests/responses to a thread pool and thanks to the suspend/resume it was pretty easy. We found this solution more lightweight.

But maybe, what we done is just plain wrong ?

 

Thanks for your help

Regards

David.

 

 

De : Oleksiy Stashok [mailto:oleksiy.stashok_at_oracle.com]
Envoyé : mercredi 19 janvier 2011 18:17
À : Gay David (Annecy)
Cc : users_at_grizzly.java.net
Objet : Re: Problem with Suspend/Resume

 

Oh, btw, here are updated test sources for MyAdapter and MyExecutor I can propose.

 

WBR,

Alexey.

 

 

package com.acme;

 

import com.sun.grizzly.tcp.Adapter;

import com.sun.grizzly.tcp.Request;

import com.sun.grizzly.tcp.Response;

import com.sun.grizzly.util.buf.ByteChunk;

import java.io.IOException;

import java.util.concurrent.SynchronousQueue;

import java.util.concurrent.ThreadPoolExecutor;

import java.util.concurrent.TimeUnit;

 

/**

 *

 */

public class MyAdapter implements Adapter

{

    private ThreadPoolExecutor executor;

    private ByteChunk bc;

    private boolean suspendMode;

 

    public MyAdapter( boolean suspendMode )

        throws IOException

    {

        executor = new ThreadPoolExecutor( 0, 500, 5*60, TimeUnit.SECONDS, new SynchronousQueue<Runnable>() );

        bc = new ByteChunk();

        bc.append( "pong".getBytes(), 0, 4 );

        this.suspendMode = suspendMode;

    }

 

    @Override

            public void service( Request request, Response response ) throws Exception

    {

        if( suspendMode )

        {

            response.suspend();

            executor.execute( new MyExecutor(request,response,bc) );

        }

        else

        {

            response.setStatus( 200 );

            response.setMessage( "Sounds good" );

            response.doWrite( bc );

            response.flush();

        }

    }

 

    @Override

            public void afterService( Request request, Response response ) throws Exception

    {

// request.recycle();

// response.recycle();

    }

}

 

 

 

package com.acme;

 

import com.sun.grizzly.tcp.Request;

import com.sun.grizzly.tcp.Response;

import com.sun.grizzly.util.buf.ByteChunk;

 

/**

 *

 * @author dGay

 */

public class MyExecutor implements Runnable

{

    Request req;

    Response res;

    ByteChunk bc;

 

    public MyExecutor( Request req, Response res, ByteChunk bc )

    {

        this.req = req;

        this.res = res;

        this.bc = bc;

    }

 

    @Override

    public void run()

    {

        try

        {

            // Thread.sleep( 5 );

            res.setStatus( 200 );

            res.setMessage( "Sounds good" );

            res.doWrite( bc );

            res.flush();

            

        }

        catch( Exception ex )

        {

            System.out.println( "\n\tException while writing response !" );

            ex.printStackTrace( System.out );

            System.out.println();

        }

        finally

        {

            try

            {

                    res.resume();

            } catch (Exception ex)

            {

                System.out.println( "\n\tException while resuming !" );

                ex.printStackTrace( System.out );

                System.out.println();

            }

        }

    }

}

 

On Jan 19, 2011, at 17:55 , Gay David (Annecy) wrote: