开发服务器上的GAE / Java LocalChannelFailureException

时间:2013-11-30 12:34:50

标签: google-app-engine channel-api

我已将Channel API (Java)与Google App Engine一起用于我的网络应用程序。我已经实现了令牌重用机制,以便不超过Channel API Quotas那么快。 这意味着,只要ChannelService.createChannel()调用收到的令牌的到期时间尚未结束,我的实现就会为刷新页面的用户重用现有通道。

刷新页面时,我得到以下异常(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)
...

我重复使用以下类别的令牌:

调用ChannelService.createChannel()时,我将过期日期和生成的令牌保存在名为"频道"

的实体中
public class Channel {
    private String id;
    private String token;
    private Date expiration;
}

然后我有一个ChannelService类,它返回一个有效的Channel及其get()方法。 channelDAO是一个只使用Map存储频道的类。因此,没有数据库持久性,这将使服务器重新启动时令牌保持活动状态。

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;
}

3 个答案:

答案 0 :(得分:4)

我通过进一步调查异常来源来解决问题。 Channel API适用于每500ms执行一次的轮询请求。我使用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”。页面刷新后,它是“connection-1”。但是,由于旧页面使用延迟执行轮询,因此会向服务器发送一个错误请求(仍然是连接-0),结果抛出异常。

我通过手动取消延迟执行来解决问题,当使用jQuery离开页面时。

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

答案 1 :(得分:1)

应仔细检查您的令牌重用方案是否存在错误,因为每次重新加载页面时都不会发生该异常。

有一个known issue after local server restarts,但如上所述,它只应该在重新启动开发服务器的时候。

答案 2 :(得分:0)

我使用GWT和gwt-gae-channel时遇到了同样的问题。解决方案就像:

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

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