+1

MONITORING SIDEKIQ USING AWS LAMBDA AND SLACK

Khi sidekiq thực hiện các công việc trong hàng đợi, rất có thể sẽ xảy ra lỗi, thay vì việc nhận được email thông báo thì chúng ta có thể đông bộ thông báo tới slack để quản lý dễ dàng hơn. Vấn đề Công việc nền thường là các công việc tương tác với api của bên thứ 3, thất bại không phải là một bất ngờ lớn, Các Api có thể bị lỗi, kết nối mạng có thể bị lỗi nên sidekiq sẽ thử lại trong các trương hợp đó. Trong trương hợp bình thường việc thử lại có thể giải quyết được vấn đề Nhưng cũng có khi vấn đê phức tạp cân thử lại số lần nhiều hơn, việc thử lại này ảnh hưởng tới chất lượng của ứng dụng. Chúng ta có thể dùng Sidekiq Web UI với quyền admin để theo dõi số lần thử lại của sidekiq. Nhưng đây không phải là cách tiện lợi nhất, chúng ta có thể đông bộ tới slack để hiển thị số lần thử lại của sidekiq. Giải pháp Có một vài lựa chọn.

  1. Add the Sidekiq polling and Slack notification vào main application rồi thiết lập Cron job
  2. Tạo 1 chương trinh riêng chỉ để thực hiện công việc trên
  3. Cài đặt một AWS Lambda để xử lý các logic.

Hai cách đầu có thể hoạt động tốt nhưng làm ứng dụng thêm phức tạp, gây mất thời gian trong việc quản lý một ứng dụng khác mà thực ra không cần thiết phải làm như vậy cho vấn đề này. Chúng ta sẽ lựa chọn AWS Lambda, triển khai cài đặt thôi. Sidekiq Queue Data Endpoint Chúng ta sẽ tạo 1 routes để trả về thông tin cơ bản của hệ thống sidekiq

require 'sidekiq/api'

class SidekiqQueuesController < ApplicationController
  skip_before_action :require_authentication

  def index
    base_stats = Sidekiq::Stats.new
    stats = {
       enqueued: base_stats.enqueued,
       queues: base_stats.queues,
       busy: Sidekiq::Workers.new.size,
       retries: base_stats.retry_size
    }

    render json: stats
  end
end

với route:

resources :sidekiq_queues, only: [:index]

Slack Incoming WebHook Chúng ta cần resuest post tới slack khi số lần thử lại của sidekiq lớn hơn 50 chằng hạn.Để làm được điều này cần config webhook integration trong Slack. Trong Slack chọn Apps & integrations -> Manage -> Custom Integrations. Có 2 lựa chọn:

  1. Incoming WebHooks
  2. Slash Commands.

Chúng ta chọn Incoming Webhooks -> Add Configuration để tạo mới 1 config. Chỗ này cần cung cấp thông tin cụ thể về kênh sẽ hiện thông báo Quan trọng nhất của bước này là để có được URL Webhook. Đây sẽ là URL mà sẽ POST đến từ bên trong hàm Lambda khi số lân thử lại vượt trên ngưỡng chấp chận. AWS Lambda Function Bây giờ chúng ta cần thiết lập ra số lần thử lại và Slack webhook URL trong AWS Lambda. Tạo mới một Lambda function với mặc định sử dụng node. Chúng ta sử dụng "CloudWatch Events – Schedule": Tại đây nhập tên và mô tả cho các luật và thời gian cập nhật, kích hoạt trigger. Tiếp theo chúng ra sẽ cung cấp tên function và chọn môi trương node mới nhất . Sử dụng code sau:

var url = require('url');
var https = require('https');
var sidekiqURL, hookUrl, slackChannel, retryThreshold;

sidekiqUrl = '[Sidekiq queue JSON endpoint]'
hookUrl = '[Slack Incoming WebHooks URL w/ token]';
slackChannel = '#operations';  // Enter the Slack channel to send a message to
retryThreshold = 50;

var postMessageToSlack = function(message, callback) {
    var body = JSON.stringify(message);
    var options = url.parse(hookUrl);
    options.method = 'POST';
    options.headers = {
        'Content-Type': 'application/json',
        'Content-Length': Buffer.byteLength(body),
    };

    var postReq = https.request(options, function(res) {
        var chunks = [];
        res.setEncoding('utf8');
        res.on('data', function(chunk) {
            return chunks.push(chunk);
        });
        res.on('end', function() {
            var body = chunks.join('');
            if (callback) {
                callback({
                    body: body,
                    statusCode: res.statusCode,
                    statusMessage: res.statusMessage
                });
            }
        });
        return res;
    });

    postReq.write(body);
    postReq.end();
};

var getQueueStats = function(callback) {
    var options = url.parse(sidekiqUrl);
    options.headers = {
        'Accept': 'application/json',
    };

    var getReq = https.request(options, function(res){
        var body = '';

        res.setEncoding('utf8');

        //another chunk of data has been recieved, so append it to `str`
        res.on('data', function (chunk) {
            body += chunk;
        });

        //the whole response has been recieved, so we just print it out here
        res.on('end', function () {
            if (callback) {
                callback({
                    body: JSON.parse(body),
                    statusCode: res.statusCode,
                    statusMessage: res.statusMessage
                });
            }
        });
    })

    getReq.end();
}

var processEvent = function(event, context) {
    getQueueStats(function(stats){
        console.log('STATS: ', stats.body);

        var retries = stats.body.retries;

        if (retries > retryThreshold) {
            var slackMessage = {
                channel: slackChannel,
                text: "www Sidekiq retries - " + retries
            };

            postMessageToSlack(slackMessage, function(response) {
                if (response.statusCode < 400) {
                    console.info('Message posted successfully');
                    context.succeed();
                } else if (response.statusCode < 500) {
                    console.error("Error posting message to Slack API: " + response.statusCode + " - " + response.statusMessage);
                    context.succeed();  // Don't retry because the error is due to a problem with the request
                } else {
                    // Let Lambda retry
                    context.fail("Server error when processing message: " + response.statusCode + " - " + response.statusMessage);
                }
            });
        } else {
            console.info('Sidekiq retries were ' + retries + ' . Below threshold.');
            context.succeed();
        }
    })
};

exports.handler = function(event, context) {
    processEvent(event, context);
};

Lưu ý: cần phải xác định sidekiqURL và hookURL với các giá trị thích hợp để làm việc. Review Chúng ta có thể xem lại các bản ghi chức năng Lambda trên CloudWatch. Truy cập CloudWatch và chọn "Nhật ký" từ trình đơn bên trái. Từ đây, các bản ghi cho mỗi lần gọi hàm Lambda sẽ được nhóm vào một luồng nhật ký: Được nhóm theo thời gian, mỗi liên kết sẽ chứa nhiều lời kêu gọi. Một thao tác đơn được bọc bằng START và END, như thể hiện trong nhật ký. Thông báo ở giữa sẽ là cuộc gọi đến console.log. Nó sã ghi lại kết quả của cuộc thăm dò hàng đợi Sidekiq cho các mục đích gỡ lỗi, vì vậy bạn có thể thấy như thế này: Số lần thử lại là 9 < 50 nên chưa post tới Slack Chúng ta có thể nhìn thấy bài viết đăng thành công đăng nhập cho thấy thông điệp đã được gửi tới Slack's webhook. Cuối cùng, đây là những gì mà thông báo kết quả giống như trong Slack khi số lần thử lại của Sidekiq vượt quá ngưỡng của chúng ta:


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí