Redis
 sql >> Teknologi Basis Data >  >> NoSQL >> Redis

Mengakses variabel dalam utas Rails

DIPERBARUI EDIT AT AKHIR:Menunjukkan kode kerja. Modul utama tidak dimodifikasi kecuali untuk kode debug. Catatan:Saya memang mengalami masalah yang telah saya catat tentang perlunya berhenti berlangganan sebelum penghentian.

Kode terlihat benar. Saya ingin melihat bagaimana Anda membuat instance-nya.

Di config/application.rb, Anda mungkin memiliki setidaknya sesuatu seperti:

require 'ws_communication'
config.middleware.use WsCommunication

Kemudian, di klien JavaScript Anda, Anda harus memiliki sesuatu seperti ini:

var ws = new WebSocket(uri);

Apakah Anda membuat instance lain dari WsCommunication? Itu akan mengatur @clients ke array kosong dan dapat menunjukkan gejala Anda. Sesuatu seperti ini akan salah:

var ws = new WsCommunication;

Akan membantu kami jika Anda akan menunjukkan klien dan, mungkin, config/application.rb jika posting ini tidak membantu.

Omong-omong, saya setuju dengan komentar bahwa @clients harus dilindungi oleh mutex pada pembaruan apa pun, jika tidak dibaca juga. Ini adalah struktur dinamis yang dapat berubah kapan saja dalam sistem yang digerakkan oleh peristiwa. redis-mutex adalah pilihan yang baik. (Semoga tautan itu benar karena Github tampaknya membuat 500 kesalahan pada semua hal saat ini.)

Anda mungkin juga memperhatikan bahwa $redis.publish mengembalikan nilai bilangan bulat dari jumlah klien yang menerima pesan.

Terakhir, Anda mungkin perlu memastikan bahwa saluran Anda dihentikan langganannya sebelum dihentikan. Saya pernah mengalami situasi di mana saya akhirnya mengirim setiap pesan beberapa kali, bahkan berkali-kali, karena langganan sebelumnya ke saluran yang sama yang tidak dibersihkan. Karena Anda berlangganan saluran di dalam utas, Anda harus berhenti berlangganan di utas yang sama atau prosesnya hanya akan "menggantung" menunggu utas yang tepat muncul secara ajaib. Saya menangani situasi itu dengan menetapkan bendera "berhenti berlangganan" dan kemudian mengirim pesan. Kemudian, di dalam blok on.message, saya menguji tanda berhenti berlangganan dan mengeluarkan tanda berhenti berlangganan di sana.

Modul yang Anda berikan, dengan hanya sedikit modifikasi debug:

require 'faye/websocket'
require 'redis'

class WsCommunication
  KEEPALIVE_TIME = 15 #seconds
  CHANNEL = 'vip-deck'

  def initialize(app)
    @app = app
    @clients = []
    uri = URI.parse(ENV['REDISCLOUD_URL'])
    $redis = Redis.new(host: uri.host, port: uri.port, password: uri.password)
    Thread.new do
      redis_sub = Redis.new(host: uri.host, port: uri.port, password: uri.password)
      redis_sub.subscribe(CHANNEL) do |on|
        on.message do |channel, msg|
          puts "Message event. Clients receiving:#{@clients.count};"
          @clients.each { |ws| ws.send(msg) }
        end
      end
    end
  end

  def call(env)
    if Faye::WebSocket.websocket?(env)
      ws = Faye::WebSocket.new(env, nil, {ping: KEEPALIVE_TIME})

      ws.on :open do |event|
        @clients << ws
        puts "Open event. Clients open:#{@clients.count};"
      end

      ws.on :message do |event|
        receivers = $redis.publish(CHANNEL, event.data)
        puts "Message published:#{event.data}; Receivers:#{receivers};"
      end

      ws.on :close do |event|
        @clients.delete(ws)
        puts "Close event. Clients open:#{@clients.count};"
        ws = nil
      end

      ws.rack_response
    else
      @app.call(env)
    end
  end
end

Kode pelanggan uji yang saya berikan:

# encoding: UTF-8
puts "Starting client-subscriber.rb"
$:.unshift File.expand_path '../lib', File.dirname(__FILE__)
require 'rubygems'
require 'eventmachine'
require 'websocket-client-simple'

puts "websocket-client-simple v#{WebSocket::Client::Simple::VERSION}"

url = ARGV.shift || 'ws://localhost:3000'

EM.run do

  ws = WebSocket::Client::Simple.connect url

  ws.on :message do |msg|
    puts msg
  end

  ws.on :open do
    puts "-- Subscriber open (#{ws.url})"
  end

  ws.on :close do |e|
    puts "-- Subscriber close (#{e.inspect})"
    exit 1
  end

  ws.on :error do |e|
    puts "-- Subscriber error (#{e.inspect})"
  end

end

Kode penerbit uji yang saya berikan. Penerbit dan Pelanggan dapat dengan mudah digabungkan, karena ini hanyalah pengujian:

# encoding: UTF-8
puts "Starting client-publisher.rb"
$:.unshift File.expand_path '../lib', File.dirname(__FILE__)
require 'rubygems'
require 'eventmachine'
require 'json'
require 'websocket-client-simple'

puts "websocket-client-simple v#{WebSocket::Client::Simple::VERSION}"

url = ARGV.shift || 'ws://localhost:3000'

EM.run do
  count ||= 0
  timer = EventMachine.add_periodic_timer(5+rand(5)) do
    count += 1
    send({"MESSAGE": "COUNT:#{count};"})
  end

  @ws = WebSocket::Client::Simple.connect url

  @ws.on :message do |msg|
    puts msg
  end

  @ws.on :open do
    puts "-- Publisher open"
  end

  @ws.on :close do |e|
    puts "-- Publisher close (#{e.inspect})"
    exit 1
  end

  @ws.on :error do |e|
    puts "-- Publisher error (#{e.inspect})"
    @ws.close
  end

  def self.send message
    payload = message.is_a?(Hash) ? message : {payload: message}
    @ws.send(payload.to_json)
  end
end

Contoh config.ru yang menjalankan semua ini di lapisan middleware rak:

require './controllers/main'
require './middlewares/ws_communication'
use WsCommunication
run Main.new

Ini adalah Utama. Saya menghapusnya dari versi saya yang sedang berjalan sehingga mungkin perlu diubah jika Anda menggunakannya:

%w(rubygems bundler sinatra/base json erb).each { |m| require m }
ENV['RACK_ENV'] ||= 'development'
Bundler.require
$: << File.expand_path('../', __FILE__)
$: << File.expand_path('../lib', __FILE__)

Dir["./lib/*.rb", "./lib/**/*.rb"].each { |file| require file }
env = ENV['OS'] == 'Windows_NT' ? 'development' : ENV['RACK_ENV']

  class Main < Sinatra::Base

    env = ENV['OS'] == 'Windows_NT' ? 'development' : ENV['RACK_ENV']
    get "/" do
      erb :"index.html"
    end

    get "/assets/js/application.js" do
      content_type :js
      @scheme = env == "production" ? "wss://" : "ws://"
      erb :"application.js"
    end
  end


  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Redis sebagai generator id atom unik - Utas cara aman untuk aplikasi web untuk menghindari kondisi balapan

  2. parameter maxmemory di redis.conf

  3. Redis + ActionController::Utas langsung tidak mati

  4. Apakah ada analog MGET untuk hash Redis?

  5. Pengecualian waktu habis setelah perintah asinkron dan Tugas. Saat Apa pun menunggu di StackExchange. Redis