lanrion / weixin_authorize

微信 Ruby 高级API weixin_authorize http://github.com/lanrion/weixin_authorize .
MIT License
322 stars 116 forks source link

Redis after Forking disconnected 的问题 #62

Closed u0x01 closed 9 years ago

u0x01 commented 9 years ago

似乎在 access_token 过期后会出现 Tried to use a connection from a child process without reconnecting. You need to reconnect to Redis after forking. 的问题

请问是插件逻辑不完善还是我配置有问题?

lanrion commented 9 years ago

跟 #8 这个是同样的问题,属于redis-rb的问题,之前通过升级redis-rb后解决了这个问题,麻烦贴一下你的Redis的版本与weixin_authorize的版本。 btw,后面会去掉插件默认使用redis存储token的方案。

u0x01 commented 9 years ago

weixin_authorize 1.6.0 weixin_rails_middleware 1.3.0 redis 3.0.7

我的 Gem list 中似乎没有引入 redis-rb, 是需要手动引入吗?

$bundle
Using rake 10.4.2
Using i18n 0.7.0
Using json 1.8.3
Using minitest 5.8.0
Using thread_safe 0.3.5
Using tzinfo 1.2.2
Using activesupport 4.2.3
Using builder 3.2.2
Using erubis 2.7.0
Using mini_portile 0.6.2
Using nokogiri 1.6.6.2
Using rails-deprecated_sanitizer 1.0.3
Using rails-dom-testing 1.0.7
Using loofah 2.0.2
Using rails-html-sanitizer 1.0.2
Using actionview 4.2.3
Using rack 1.6.4
Using rack-test 0.6.3
Using actionpack 4.2.3
Using globalid 0.3.6
Using activejob 4.2.3
Using mime-types 2.6.1
Using mail 2.6.3
Using actionmailer 4.2.3
Using activemodel 4.2.3
Using arel 6.0.3
Using activerecord 4.2.3
Using execjs 2.6.0
Using autoprefixer-rails 5.2.1.2
Using debug_inspector 0.0.2
Using binding_of_caller 0.7.2
Using sass 3.4.16
Using bootstrap-sass 3.2.0.2
Using columnize 0.9.0
Using byebug 5.0.0
Using carrierwave 0.10.0
Using coffee-script-source 1.9.1.1
Using coffee-script 2.4.1
Using thor 0.19.1
Using railties 4.2.3
Using coffee-rails 4.1.0
Using unf_ext 0.0.7.1
Using unf 0.1.4
Using domain_name 0.5.24
Using http-cookie 1.0.2
Using multi_json 1.11.2
Using jbuilder 2.3.1
Using jquery-rails 4.0.4
Using subexec 0.2.3
Using mini_magick 3.7.0
Using multi_xml 0.5.5
Using netrc 0.10.3
Using nprogress-rails 0.1.6.7
Using pg 0.18.2
Using bundler 1.10.6
Using sprockets 3.3.1
Using sprockets-rails 2.3.2
Using rails 4.2.3
Using rdoc 4.2.0
Using redis 3.0.7
Using redis-namespace 1.4.1
Using rest-client 1.8.0
Using roxml 3.3.1
Using tilt 1.4.1
Using sass-rails 5.0.3
Using sdoc 0.4.1
Using spring 1.3.6
Using turbolinks 2.5.3
Using uglifier 2.7.1
Using web-console 2.2.1
Using yajl-ruby 1.2.1
Using weixin_authorize 1.6.0
Using weixin_rails_middleware 1.3.0
u0x01 commented 9 years ago

这个问题有没有可能是因为用了 redis 定时删除 access_token 而产生了 Fork 如果手动实现是不是能避免这个问题?:

class WeixinToken
    def get_access_token(*enforce_refresh)
      if enforce_refresh.nil?
        enforce_refresh = false
      end

      last_data = @redis.get('weixin_access_token')
      if !last_data.nil?
        last_data = JSON.parse last_data
      end

      if enforce_refresh == true || last_data.nil? || (Time.now.to_i - last_data['last_get_time'].to_i) > 120*60

        apiUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=#{$WEIXIN_APPID}&secret=#{$WEIXIN_APPSECRET}"
        response = Net::HTTP.get(URI apiUrl)
        response = JSON.parse response

        access_token = response['access_token']
        data = Hash.new
        if !last_data.nil?
          data[:last_access_token] = last_data['access_token']
          data[:get_times_today] = last_data['get_times_today'].to_i + 1 # 记录当日API调用次数,以便检查问题
          if (Time.now.to_a[7] - last_data['get_begin_time']) != 0
            data[:get_begin_time] = Time.now.to_i
            data[:get_times_today] = 1
          else
            data[:get_begin_time] = last_data['get_begin_time']
          end
        else
           # 清空当日API调用次数
          data[:get_begin_time] = Time.now.to_a[7] # 7:一年中的第几天
          data[:get_times_today] = 1 
        end
        data[:access_token] = access_token
        data[:last_get_time] = Time.now.to_i

        @redis.set 'weixin_access_token', data.to_json
        access_token
      else
        last_data['access_token']
      end

    end

    def get_last_access_token
      last_data = @redis.get('weixin_access_token')
      if !last_data.nil?
        last_data = JSON.parse last_data
        last_data['access_token']
      else
        nil
      end
    end
  end
lanrion commented 9 years ago

redis-rb 就是 redis :baby_chick:

这个错误是由redis-rb中 ensure_connected raise的,根据文档,是为了当I/O错误可以重连接。 缓存失效导致也有可能,之前接触过有不少使用redis-rb的开源项目,多少都会碰到这个问题。

另外,如果要解决这个问题,如果你的场景是一个公共号的话,是可以不使用redis来缓存token的:

$client ||= WeixinAuthorize::Client.new(ENV["APPID"], ENV["APPSECRET"])

如果一定要使用的话,可以通过传入custom_access_token,即通过自己方式获取的access_token来灵活处理: 注意此方法只适用于Master分支 Gemfile:

gem 'weixin_authorize', git: "https://github.com/lanrion/weixin_authorize.git", branch: :master
$client ||= WeixinAuthorize::Client.new(ENV["APPID"], ENV["APPSECRET"], {custom_access_token: "your_custom_access_token"})
lanrion commented 9 years ago

我会跟进这个问题的。

u0x01 commented 9 years ago

感谢,另外可以弱弱的问下ENV["XXX"]是在 bash 里面 export XXX = VALUE 这样设置吗?

lanrion commented 9 years ago

对的,ENV那个是环境变量,你可以用其他方式代替。

@u0x010 :scream: 不好意思,我刚刚发现你的版本号不对,请升级:

gem 'weixin_authorize', ~> "1.6.3"

安装完之后并确保查看你的redis是"redis", ">= 3.1.0"

试试升级。

u0x01 commented 9 years ago

其实我根本就没写版本号 😛 我以为这样用就是最新版。 我加上版本号 bundle update 以后再试试看以后会不会出问题。

另外,可以一起讨论下如何完善卡券功能吗?

我实在有些佩服微信卡券项目组的人,能想到的需求都有了,没有想到的也有了。

但是他那个Json构造让我感觉心好累:好几种不同类型的卡券参数直接放在一起 这里有一份我整理好的微信卡券接口参数Map

创建卡券的 Json 嵌套了好几层,我都不知道怎么设计 Model 了。

我现在就是用的笨方法 rails g model Weixin/Card rails g model Weixin/CardCustomField rails g model Weixin/CardCustomCell rails g model Weixin/CardBaseInfo rails g model Weixin/CardBaseInfoSku rails g model Weixin/CardBaseInfoDateInfo

但是我觉得这样的逻辑太重了,不好管理

@lanrion 大大能给点建议吗

lanrion commented 9 years ago

指定就可以了,然后bundle install,就可以升级了。 gem 'weixin_authorize', ~> "1.6.3"

u0x01 commented 9 years ago

我这里用的淘宝源,好像找不到这个版本

Bundler could not find compatible versions for gem "redis":
  In Gemfile:
    redis-namespace (~> 1.4.1) ruby depends on
      redis (~> 3.0.4) ruby

    weixin_authorize (~> 1.6.3) ruby depends on
      redis (>= 3.1.0) ruby

先这样啦! 晚上用官方源试试看,升级以后还会不会这样。

总之谢谢你 🙏 创造出这么精彩易用的Gem。

lanrion commented 9 years ago

把Gemfile.lock删除,再重新试试。