How to config vaadin write session to memcached

Hi all,
I found vaadin’ session is a memory-killer…when amount of concurrent user access the application,online session will increase quickly ,outofmemory will occur soon,
So,I want to write session content to memcached.but how to?any existed solution or addon to this issue?

Thanks

L.J.W

Hi,

  1. Before looking to complicate your deployment setup, I would first check that you are not holding onto any memory necessarily. Remember, anything transitively connected to the Application instance will remain in the session; I would recommend examining your session usage using a profiler.

  2. I am not aware of any Vaadin plugins to do what you want; however, my first port of call would be to look at my Web Application Server to see if there are any solutions there to storing your session in an external cache such as memcache [1]

  1. If you wanted to roll your own (storage and retrieval of Application instance outside of the http session), I would suggest that you look at overriding AbstractApplicationServlet#getExistingApplication.

Cheers,

Charles

[1]
Since, logically, there are many many more people using a particular web application server than there are using Vaadin - therefore, it is more likely that someone has worked on this for the application server than the framework!

Thanks for your reply,I have implements ApplicationServlet basing GAEApplicationServlet codebase.and This work fine.
Here is the my code:



public class MemcachedApplicationServlet extends ApplicationServlet {

    private static final Logger logger = Logger.getLogger(MemcachedApplicationServlet.class.getName());

    // memcache mutex is MUTEX_BASE + sessio id
    private static final String MUTEX_BASE = "_vmutex";

    // used identify ApplicationContext in memcache and datastore
    private static final String AC_BASE = "_vac";

    // UIDL requests will attempt to gain access for this long before telling
    // the client to retry
    private static final int MAX_UIDL_WAIT_MILLISECONDS = 5000;

    // Tell client to retry after this delay.
    // Note: currently interpreting Retry-After as ms, not sec
    private static final int RETRY_AFTER_MILLISECONDS = 100;

    // Properties used in the datastore
    private static final String PROPERTY_EXPIRES = "expires";
    private static final String PROPERTY_DATA = "data";

    // path used for cleanup
    private static final String CLEANUP_PATH = "/CLEAN";
    // max entities to clean at once
    private static final int CLEANUP_LIMIT = 200;
    // appengine session kind
    private static final String APPENGINE_SESSION_KIND = "_ah_SESSION";
    // appengine session expires-parameter
    private static final String PROPERTY_APPENGINE_EXPIRES = "_expires";

    private static int count = 0;

    private static Object LOCK = new Object();

    protected void sendDeadlineExceededNotification(HttpServletRequest request,
                                                    HttpServletResponse response) throws IOException {
        criticalNotification(
                request,
                response,
                "Deadline Exceeded",
                "I'm sorry, but the operation took too long to complete. We'll try reloading to see where we're at, please take note of any unsaved data...",
                "", null);
    }

    protected void sendNotSerializableNotification(HttpServletRequest request,
                                                   HttpServletResponse response) throws IOException {
        criticalNotification(
                request,
                response,
                "NotSerializableException",
                "I'm sorry, but there seems to be a serious problem, please contact the administrator. And please take note of any unsaved data...",
                "", getApplicationUrl(request).toString()
                + "?restartApplication");
    }

    protected void sendCriticalErrorNotification(HttpServletRequest request,
                                                 HttpServletResponse response) throws IOException {
        criticalNotification(
                request,
                response,
                "Critical error",
                "I'm sorry, but there seems to be a serious problem, please contact the administrator. And please take note of any unsaved data...",
                "", getApplicationUrl(request).toString()
                + "?restartApplication");
    }

    @Override
    protected void service(HttpServletRequest request,
                           HttpServletResponse response) throws ServletException, IOException {


        initPool();

        if (isCleanupRequest(request)) {
            cleanDatastore();
            return;
        }

        RequestType requestType = getRequestType(request);

        if (requestType == RequestType.STATIC_FILE) {
            // no locking needed, let superclass handle
            super.service(request, response);
            cleanSession(request);
            return;
        }

        if (requestType == RequestType.APPLICATION_RESOURCE) {
            // no locking needed, let superclass handle
            getApplicationContext(request);
            super.service(request, response);
            cleanSession(request);
            return;
        }

        final HttpSession session = request
                .getSession(requestCanCreateApplication(request, requestType));
        if (session == null) {
            handleServiceSessionExpired(request, response);
            cleanSession(request);
            return;
        }

        long startTime = System.currentTimeMillis();

        try {


            // de-serialize or create application context, store in session
            ApplicationContext ctx = getApplicationContext(request);

            super.service(request, response);

            // serialize
            String id = AC_BASE + session.getId();
            mc.set(id, ctx);

        } catch (NotSerializableException e) {
            logger.log(Level.SEVERE, "Not serializable!", e);

            // TODO this notification is usually not shown - should we redirect
            // in some other way - can we?
            sendNotSerializableNotification(request, response);
        } catch (Exception e) {
            logger.log(Level.WARNING,
                    "An exception occurred while servicing request.", e);

            sendCriticalErrorNotification(request, response);
        } finally {
            // "Next, please!"
            cleanSession(request);

            long endTime = System.currentTimeMillis();
            synchronized (LOCK) {
                count++;
                System.out.println("count:" + count + ",time:" + (endTime - startTime) + "ms\n");
            }
        }
    }

    protected ApplicationContext getApplicationContext(HttpServletRequest request) {
        HttpSession session = request.getSession();
        String id = AC_BASE + session.getId();
        ApplicationContext applicationContext = (ApplicationContext) mc.get(id);
        if (applicationContext != null) {
            session.setAttribute(WebApplicationContext.class.getName(),
                    applicationContext);
        }

        // will create new context if the above did not
        return getApplicationContext(session);

    }

    private boolean isCleanupRequest(HttpServletRequest request) {
        String path = getRequestPathInfo(request);
        if (path != null && path.equals(CLEANUP_PATH)) {
            return true;
        }
        return false;
    }

    /**
     * Removes the ApplicationContext from the session in order to minimize the
     * data serialized to datastore and memcache.
     *
     * @param request
     */
    private void cleanSession(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if (session != null) {
            session.removeAttribute(WebApplicationContext.class.getName());
        }
    }

    /**
     * This will look at the timestamp and delete expired persisted Vaadin and
     * appengine sessions from the datastore.
     * <p/>
     * TODO Possible improvements include: 1. Use transactions (requires entity
     * groups - overkill?) 2. Delete one-at-a-time, catch possible exception,
     * continue w/ next.
     */
    private void cleanDatastore() {
        //TODO
    }


    protected MemCachedClient mc = null;

    protected void initPool() {
        if (mc == null) {
            ServletContext servletContext = getServletContext();
            org.springframework.context.ApplicationContext applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
            mc = (MemCachedClient) applicationContext.getBean("memcachedClient");
        }
    }


}