Comments (16)
首先恭喜站点流量那么大,然后我改了一下刷新token的算法,现在不是在同一个时间刷access_token了,而是会在过期前3分钟到过期前30秒的一个随机时间,我觉得这样就应该不会常发生这样的情况了,不过这种情况也只有靠你试验了。:smile:
还有现在master版本刚刚从Rest-Client迁移到http,要不你也帮忙测一下?
from wechat.
还有我在计划将token的存取从文件移到redis或者环境变量中,这样就可以支持Heroku或者你的这种大流量情况了。@jasper-fu
from wechat.
赞,那我直接升级到最新的去 👏
from wechat.
流量并不大,只是刚好那时一堆人在一起测试 😢
from wechat.
发现这样似乎并不能解决我说到的问题。我看了一下代码,不知道是不是理解的问题,发现那个主动检查 token 有效期的代码只会在 initialize 的时候检查,然后就不会调用到了。
在 lib/wechat/api.rb
里,有下面这段
module Wechat
class Api < ApiBase
API_BASE = 'https://api.weixin.qq.com/cgi-bin/'
OAUTH2_BASE = 'https://api.weixin.qq.com/sns/oauth2/'
def initialize(appid, secret, token_file, timeout, skip_verify_ssl, jsapi_ticket_file)
@client = Client.new(API_BASE, timeout, skip_verify_ssl)
@access_token = AccessToken.new(@client, appid, secret, token_file)
@jsapi_ticket = JsapiTicket.new(@client, @access_token, jsapi_ticket_file)
end
# ...
end
end
所以后面调用 Wechat.api.xxx
接口时候读到的 access_token 都是这里的那个实例变量,一个 worker 调用比如 media 这个 api 的时候发现 invalid token 的错误了,回去刷新 access_token
。然后另一个 worker 调用会继续刷新 access_token,我理解的没错的话,多个 worker 的情况下,由于进程间是独立的,会导致 access_token 一直被刷新,糟糕的情况就是四个 worker 同时在工作,这时一起刷新 access_token 就出现我开始说的问题了。
from wechat.
不是在initialize里面检查,是在取token的时候,token在文件里面如果是对的就不会发生这个问题了,但是如果四个worker同时取,而且初始的时候token还是错的,那么是有可能死锁的,建议随便执行一条wechat命令预先刷新对就好了。
这部分的确应该写的更好一点。。
access_token.rb
def token
begin
@token_data ||= JSON.parse(File.read(token_file))
created_at = token_data['created_at'].to_i
expires_in = token_data['expires_in'].to_i
fail 'token_data may be expired' if Time.now.to_i - created_at >= expires_in - @random_generator.rand(30..3 * 60)
rescue
refresh
end
valid_token(@token_data)
end
from wechat.
@Eric-Guo 问题在 lib/wechat.rb
这里
module Wechat
def self.api
@wechat_api ||= ApiLoader.with({})
end
end
调用 Wechat.api
的时候,第一次会 initialize,然后就到内存里了,每个 worker 有一份 copy,后面调用 Wechat.api
读的内存里的 @wechat_api
,所以后面的取 token 的时候也不会调用到 lib/wechat/access_token.rb
的 token 方法了。
我刚才测试了一下,手动修改 wechat_access_token,再去 console 里看 Wechat.api.access_token.token
数据还是修改之前的,就是 @wechat_api ||= ApiLoader.with({})
后面都是读的内存里的数据,不会再从文件里读了。所以导致后面检查更新 token 的都不会被触发,token 被更新都是因为调用微信的 api 出现 invalid token 才更新了的。
我现在 fork 了一份用比较粗糙的方法改成
def self.api
ApiLoader.with({})
end
每次都去读一次 initialize 一次
from wechat.
你是对的,我今晚看看怎么改比较好
from wechat.
想了想应该保持其他配置项缓存,token应该还是随用随取,如果是文件中,每次都应该读文件,因为token不是配置啊!
from wechat.
嗯,我也觉得应该是随用随取,不然不管是文件还是存 db 都会有上面这种问题。
from wechat.
@Eric-Guo 放到redis是靠谱的做法,我在自己的fork里面已经这么做了,非常稳定;
不过我现在用的是redis全局变量。。。没时间做重构呢~~
from wechat.
我重写了这部分代码,但是感觉每次api调用都读一次文件有点low,目前的实现是没有初始化才读,应该足够了?
def token
read_token_from_file if access_token.blank?
refresh if remain_life_seconds < @random_generator.rand(30..3 * 60)
access_token
end
from wechat.
我觉得还是有问题啊,问题不是出在这部分的文件这里,我改的之所以每次都要读文件是考虑到这种情况:
A / B worker 的内存中各有一个不一样的 token,假设 B worker 的是正确的。
这时两个 worker 同时接收到请求,然后如果 A worker 快一步然后请求不对,刷新了 token,这时 B worker 用自己的 token 去请求也得刷新 token,这时如果 A 又拿着自己的新 token 去请求就又会刷新 token,B 那边的又用不了了。。。我们昨天测试就是碰到这种情况,因为我们的公众号会和用户的互动比较频繁,所以用到 token 也比较频繁,这种情况触发的概率还是蛮大的,尤其是 worker 增加到更多的情况。
而上面的这部分改动我觉得并没有避免这种情况,还是会出现每个 worker 拿着自己内存里有可能是错误的 token 去请求。
from wechat.
恩,你说的没错,的确只能每次读文件,我写了注释。
from wechat.
坐等支持配置 access_token 存储的版本 🙊
from wechat.
由于http的版本不能upload files,暂时先发布一个0.6.9的版本,包含了这个token refresh bug的修正,这样0.6系列也算跑在最新版本的代码上(除了移除了http支持)。
from wechat.
Related Issues (20)
- 配置文件的token指的是什么? HOT 1
- wechat_api 接口对自定义小程序配置无法正确读取 HOT 8
- 微信公众平台问题 HOT 11
- 获取Ticket错误,Wechat::ResponseError - api unauthorized HOT 2
- 没有找到上传视频的api,能否实现呢? HOT 1
- 关于 JS-SDK 的疑问 HOT 1
- add ruby 3 support HOT 2
- 消息发送疑问 HOT 4
- Ruby 3.0 + Rails 6.1 shows DEPRECATION WARNING running rspec HOT 7
- 使用 wechat_responder account 无法正确加载配置 HOT 1
- 小程序MpApi的initialize 错误 HOT 3
- 能否支持响应小程序卡片消息类型miniprogrampage? HOT 1
- 请问支持企业微信的获取【会话内容存档】功能么 HOT 4
- 如何调用mp_api下关于小程序的API? HOT 1
- 微信的草稿箱功能什么时候可以支持,图文素材现在部分公众号已经用不了了 HOT 1
- An error occurred with wechat command-line 1st attempt HOT 5
- Psych::BadAlias (Unknown alias: default) HOT 2
- 请问使用wechat_responder没有响应是怎么回事? HOT 11
- 是不是要向psych (5.0.0)做一些兼容处理了? HOT 2
- Responder#on方法中关于message type的限制似乎是没必要的 HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from wechat.