• בלוג
  • באג ריפורט: אזורי זמן

באג ריפורט: אזורי זמן

הבאג הקטן הבא מראה איך דקה של חוסר תשומת לב יכולה לעלות בכמה שעות של דיבאגינג, וסיפור שהיה כך היה:

1. המערכת

המערכת עליה אנחנו מדברים מורכבת משרת מרכזי ומספר סרביסים קטנים יותר לצורך ביצוע משימות קטנות. בשביל להשאיר את הפוסט פשוט נניח שאחד הסרביסים אחראי על משלוח תזכורות לאימייל של משתתפים בפגישות.

בגלל ששליחת תזכורת לפגישה קורית הרבה אחרי שמישהו קבע פגישה, התקשורת היא אסינכרונית באמצעות Message Queue. הקוד הבא ב Rails שולח הודעה לסרביס על כל פגישה חדשה שנוצרה או עדכון לפגישה קיימת:

class CreateMeetingReminderJob < ApplicationJob
  def perform(meeting_id)
    meeting = Meeting.find(meeting_id)
    MESSAGING_SERVICE.meetings_queue.publish(
      { id: meeting.id, starts_at: meeting.starts_at }.to_json
    )
  end
end

ובצד של הסרביס הקוד הבא מושך את המידע על הפגישה ויוצר משימה מתוזמנת כדי לשלוח תזכורת:

    channel.consume(queue, async function(msg) {
      const data = JSON.parse(msg.content);
      const numRemoved = await agenda.cancel({ data: { id: data.id }});
      console.log(`canceled previous ${numRemoved} jobs`);
      agenda.schedule(data.starts_at, "send reminder", {
        id: data.id
      });
    }, { noAck: true })

2. מה המשתמשים ראו

אחרי העברת אחד הסרביסים לשרת אחר פתאום הודעות תזכורת הגיעו בשעות מוזרות או שהפסיקו להגיע בכלל. המשך מחקר הראה שהודעות תמיד מגיעות 5 שעות לפני הזמן שהן צריכות להגיע.

מכאן הדרך היתה קצרה לבחינה בלוג של ההודעות שעברו והבנה ששתי המערכות לא עובדות באותו אזור זמן. כשהמערכת המרכזית ביקשה לשלוח תזכורת לפגישה שתתקיים ב 17:00, הסרביס היה בטוח שהפגישה צריכה להתקיים ב 12:00 בצהריים.

3. איך זה קרה

אזור הזמן ב Node.JS נקבע לפי הגדרות המערכת. אפשר לראות אותו באמצעות הפעלת:

> new Date().toString()
'Sat Apr 10 2021 16:23:39 GMT+0300 (Israel Daylight Time)'

זה אומר שאם מעבירים סרביס Node.JS לשרת שמכוון לאזור זמן אחר, גם הקוד עובר לעבוד באזור הזמן של המערכת החדשה עם כל התוצאות המפתיעות הקשורות לזה.

4. מה עושים בעתיד

בכתיבת סרביסים ב Node.JS יש לוודא מה אזור הזמן לפיו כל המערכת מכוונת ולדאוג להפעיל את הסרביס באזור הזמן המתאים. ב Node.JS אנחנו צריכים לקבוע את משתנה הסביבה TZ לאזור הזמן המתאים, כלומר הפעלה כזו תעבוד באזור זמן UTC:

$ tz=UTC node reminders_service.js