2013-11-30 3 views
3

Я использую Channel API (Java) с Google App Engine для своего веб-приложения. Я реализовал механизм повторного использования токенов, который быстро не превысил Channel API Quotas. Это означает, что моя реализация повторно использует существующий канал для пользователя, который обновляет страницу до тех пор, пока время истечения токена, полученного вызовом ChannelService.createChannel(), еще не закончено.GAE/Java LocalChannelFailureException на сервере разработки

При обновлении моей страницы я получаю следующее исключение (с x, начиная с 0 и увеличиваясь для каждого обновления). Однако моя страница продолжает работать по назначению. Есть ли способ избежать исключения? Или я могу просто игнорировать исключение?

com.google.appengine.api.channel.dev.LocalChannelFailureException: Client connection with ID connection-x not found. 
at com.google.appengine.api.channel.dev.Channel.getClientMessageQueue(Channel.java:79) 
at com.google.appengine.api.channel.dev.ChannelManager.getNextClientMessage(ChannelManager.java:300) 
at com.google.appengine.api.channel.dev.LocalChannelServlet.doGet(LocalChannelServlet.java:120) 
at javax.servlet.http.HttpServlet.service(HttpServlet.java:617) 
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717) 
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511) 
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166) 
... 

Im повторное использование маркеров со следующими классами:

При вызове ChannelService.createChannel() я сохранить дату истечения и сгенерированный маркер в Сущности под названием «Канал»

public class Channel { 
    private String id; 
    private String token; 
    private Date expiration; 
} 

Тогда у меня есть ChannelService класс, который возвращает действительный канал с его get(). КаналDAO - это класс, который просто использует карту для хранения каналов. Таким образом, нет стойкости к базе данных, которая бы сохраняла токен при перезагрузке сервера.

public Channel get(String clientId) { 
    Calendar calendar = Calendar.getInstance(); 
    Channel channel = channelDAO.get(clientId); 
    if (channel == null || calendar.getTime().after(channel.getExpiration())) { 
     com.google.appengine.api.channel.ChannelService channelService = ChannelServiceFactory 
       .getChannelService(); 
     calendar.add(Calendar.MINUTE, CHANNEL_UPTIME); 
     String token = channelService.createChannel(player.toString(), CHANNEL_UPTIME); 
     channel = new Channel(clientId, token, calendar.getTime()); 
     channelDAO.persist(channel); 
    } 
    return channel; 
} 

ответ

4

Я исправил проблему путем дальнейших исследований источника исключения. API канала работает с запросами опроса, которые выполняются каждые 500 мс. Я использовал консоль Firefox, чтобы отслеживать их. Вот пример опрос:

[20:40:15.978] GET http://localhost:8080/_ah/channel/dev?command=poll&channel=920a60f9b27ece1a1ba43d251fdacf2e-channel-eqt3xi-1385927324758-{clientId}&client=connection-2 [HTTP/1.1 200 OK 0ms] 

На мой вопрос, я заявил, что исключение происходит на перезагрузки страницы, так что проблема с этим было: когда страница перезагружается, что-то (я не знаю, что именно, но я полагаю, что это имеет какое-то отношение к закрытию сокетов и повторному открытию на обновлении страницы), что приводит к тому, что клиент (последний параметр запроса GET) больше не доступен. Тем не менее, доступен новый клиент: клиент «connection- {i + 1}». Поэтому, когда вы сначала вводите страницу, клиент «connection-0». После обновления страницы это «соединение-1». Но поскольку старая страница использовала отложенное выполнение для опроса, на сервер отправляется ложный запрос (все еще соединение-0), который в результате выдает исключение.

Я исправил проблему, вручную отменив выполнение с задержкой при выходе из страницы с помощью jQuery.

var channel = new goog.appengine.Channel('${channel.token}'); 
var socket = channel.open(handler); 
$(window).on('beforeunload', function() { 
    clearTimeout(socket.pollingTimer_); 
}); 
+0

работал для меня, очень здорово! спасибо –

+0

Видимо, работает в Safari, Firefox, но не в Chrome? – cloudsurfin

1

Ваша схема повторного использования маркера должна быть тщательно проверена на наличие ошибок, поскольку это исключение не должно возникать при каждой перезагрузке страницы.

Существует known issue after local server restarts, но, как указано, это должно быть только в том случае, если сервер разработки перезагружен.

+0

Спасибо за ваш ответ. Я добавил некоторые подробности о моем механизме повторного использования. Не могли бы вы посмотреть на это и сказать, что может быть неправильным? – Jonas

0

У меня была такая же проблема с использованием GWT и gwt-gae-channel. Решение будет выглядеть примерно так:

Socket socket = channel.open(new SocketListener() {...}); 
Window.addWindowClosingHandler(new ClosingHandler() { 

      @Override 
      public void onWindowClosing(ClosingEvent event) { 
        socket.close(); 
      } 
    });