新线程中的类变量不在范围内

时间:2016-06-06 05:51:38

标签: ruby-on-rails ruby multithreading

我遇到以下问题,对于拥有更多知识或经验的人来说,这可能是直截了当的。花了整个周末试图找出它没有成功......非常感谢额外的帮助和见解,谢谢。

我有一个类变量@@clients,用于跟踪打开的websocket连接。当我从on.message块(在新线程中)的redis_sub.subscribe块内访问该变量时,该数组为空。我创建了一个测试类变量@@test,每次发生新的websocket连接时都会递增,并记录该变量,同样,日志显示@@test为0,即其初始值。

class Shrimp
    # Heroku has a 50 seconds idle connection time limit. 
    KEEPALIVE_TIME = 15 # in seconds
    @@clients = []
    @@test = 0

    class << self
        def load_session(client)
            if !client.env["rack.session"].loaded?
                client.env["rack.session"][:init] = true
            end
        end

        def get_client(user_id)
            # check if user is one of the ws clients  
            @@clients.each do |client|
                # lazily load session
                load_session(client)

                # get user_id from the session
                if(client.env["rack.session"]["warden.user.user.key"][0][0] == user_id)
                    return client
                end
            end
            nil
        end
    end

    def initialize(app)
        @app = app

        redis_uri = URI.parse(ENV["REDISCLOUD_URL"])
        # work on a separte thread not to block current thread

        Thread.new do
            redis_sub = Redis.new(host: redis_uri.host, port: redis_uri.port, password: redis_uri.password)
            redis_sub.subscribe(ENV["REDIS_CHANNEL"]) do |on| # thread blocking operation
                p [:redis_suscribe]
                p [:test, @@test]

                on.message do |channel, msg|
                    data = JSON.parse(msg)

                    p [:redis_receive_message, data]
                    p [:test, @@test]

                    client = Shrimp.get_client(data["user_id"])
                    client.send(data["thumbnail_urls"].to_json) if client
                end
            end
        end
    end

    def call(env)
        env['rack.shrimp'] = self
        if Faye::WebSocket.websocket?(env)
            puts websocket_string

            # Send every KEEPALIVE_TIME sec a ping for keeping the connection open.
            ws = Faye::WebSocket.new(env, nil, { ping: KEEPALIVE_TIME })

            ws.on :open do |event|
                puts '***** WS OPEN *****'
                @@clients << ws
                @@test = @@test + 1
                p [:test, @@test]
            end

            ws.on :message do |event|
                puts '***** WS INCOMING MESSAGE *****'
                p [:message, event.data]
                p [:test, @@test]
                @@clients.each { |client| client.send(event.data.to_json) }
            end

            ws.on :close do |event|
                puts '***** WS CLOSE *****'
                p [:close, ws.object_id, event.code, event.reason]
                @@clients.delete(ws)
                p [:test, @@test]
                ws = nil
            end

            ws.on :error do |event|
                puts '***** WS ERROR *****'
                p [:close, ws.object_id, event.code, event.reason]
            end 

            # Return async Rack response
            ws.rack_response
        else
            @app.call(env)
        end
    end
end

终端输出: enter image description here

我们可以在第一个连接打开后看到@@test类变量为1,当服务器从该客户端收到消息时仍然1,当记录时0当关闭websocket连接时,从on.message块内再次1

我显然遗漏了一些东西,但是尽管进行了所有的研究和阅读,却无法弄明白。

0 个答案:

没有答案