使用 Ruby 的 Redis 操作在 PPOLL 中被阻止



我们的项目使用这个在 centos 6.4 上运行的 apns 提供程序来推送 oofline msg 。

apns 提供程序只是使用 brpop 从 redis 队列中读取,然后重新格式化数据并发送到 apns msg 到 Apple 推送服务。

最近,我遇到了一个问题,即 apn 提供程序不会从 redis 队列中读取消息,我只是跟踪该过程:

异常跟踪结果:

tcp        0      0 ::1:39688                   ::1:6379                    ESTABLISHED 29452/ruby          
[root@server]# strace -p 29452
Process 29452 attached - interrupt to quit
ppoll([{fd=56, events=POLLIN}], 1, NULL, NULL, 8

正常的跟踪结果:

clock_gettime(CLOCK_MONOTONIC, {9266059, 349937955}) = 0
select(9, [8], NULL, NULL, {6, 0})      = 1 (in [8], left {3, 976969})
fcntl64(8, F_GETFL)                     = 0x802 (flags O_RDWR|O_NONBLOCK)
read(8, "*-1rn", 1024)                = 5
write(8, "*3rn$5rnbrpoprn$9rnapn_queuern$1"..., 37) = 37
fcntl64(8, F_GETFL)                     = 0x802 (flags O_RDWR|O_NONBLOCK)
read(8, 0x9a0e5d8, 1024)                = -1 EAGAIN (Resource temporarily unavailable)
clock_gettime(CLOCK_MONOTONIC, {9266061, 374086306}) = 0
select(9, [8], NULL, NULL, {6, 0}^C <unfinished ...>
Process 20493 detached

以下是相关代码:

loop do
        begin
          message = @redis.brpop(self.queue, 1)
          if message
              APN.log(:info, "---------->#{message} ----------->n")
              @notification = APN::Notification.new(JSON.parse(message.last,:symbolize_names => true))
              send_notification
          end
        rescue Exception => e
          if e.class == Interrupt || e.class == SystemExit
            APN.log(:info, 'Shutting down...')
            exit(0)
          end
          APN.log(:error, "class: #{e.class} Encountered error: #{e}, backtrace #{e.backtrace}")
          APN.log(:info, 'Trying to reconnect...')
          client.connect!
          APN.log(:info, 'Reconnected')
          client.push(@notification)
        end
      end

此问题不周期性地发生,周期时间可能是一两个月。

我觉得代码逻辑是对的,猜测系统网络可能会影响编程的正常运行。

当我使用 pkill [pid] 杀死程序时,它只是恢复正常的命令,开始从队列中读取 msg。

现在我不知道如何分析问题,所以我不得不使用cron重新启动或定期向程序发送终止信号。 :(

每个人都能有处理问题的想法吗?

您在异常跟踪结果 ppoll 中使用了空超时。正确的方法是

const struct timespec timeout = { .tv_sec = 10, .tv_nsec = 0 };
struct pollfd myfds;
myfds.fd = fd;
myfds.events = POLLIN;
myfds.revents = 0;
retresult = ppoll(&myfds, 1,&timeout,NULL);
一旦 10 秒

完成返回下一个代码,这将提供 10 秒的延迟。

最新更新