Computer >> कंप्यूटर >  >> प्रोग्रामिंग >> Ruby

कॉलबैक की एक जोड़ी Gotchas (और एक रेल 5 फिक्स)

ActiveRecord कॉलबैक आपके मॉडल के जीवन के विभिन्न चरणों के दौरान कोड चलाने का एक आसान तरीका है।

उदाहरण के लिए, मान लें कि आपके पास एक प्रश्नोत्तर साइट है, और आप सभी प्रश्नों को खोजने में सक्षम होना चाहते हैं। हर बार जब आप किसी प्रश्न में परिवर्तन करते हैं, तो आप उसे ElasticSearch जैसी किसी चीज़ में अनुक्रमित करना चाहेंगे। अनुक्रमण में कुछ समय लगता है और यह अत्यावश्यक नहीं है, इसलिए आप इसे साइडकीक के साथ पृष्ठभूमि में करेंगे।

यह after_save का उपयोग करने का सही समय लगता है कॉलबैक! तो अपने मॉडल में, आप कुछ इस तरह लिखेंगे:

app/models/question.rb
class Question < ActiveRecord::Base
  after_save :index_for_search

  # ...

  private
  
  def index_for_search
    QuestionIndexerJob.perform_later(self)
  end
end
ऐप/जॉब्स/question_indexer_job.rb
class QuestionIndexerJob < ActiveJob::Base
  queue_as :default

  def perform(question)
    # ... index the question ...
  end
end

यह बहुत अच्छा काम करता है! या, कम से कम, ऐसा लगता है। जब तक आप बहुत अधिक नौकरियों की कतार में नहीं लग जाते और ये त्रुटियां दिखाई नहीं देतीं:

2015-03-10T05:29:02.881Z 52530 TID-oupf889w4 WARN: Error while trying to deserialize arguments: Couldn't find Question with 'id'=3

ज़रूर, साइडकीक नौकरी के लिए फिर से प्रयास करेगा और यह शायद अगली बार काम करेगा। लेकिन यह अभी भी थोड़ा अजीब है। साइडकीक को वह प्रश्न क्यों नहीं मिल रहा है जिसे आपने अभी सहेजा है?

प्रक्रियाओं के बीच एक दौड़ की स्थिति

रेल कॉल after_save रिकॉर्ड सहेजने के तुरंत बाद कॉलबैक। लेकिन उस रिकॉर्ड को अन्य डेटाबेस कनेक्शन द्वारा नहीं देखा जा सकता है, जैसे कि एक साइडकीक उपयोग कर रहा है, जब तक कि डेटाबेस लेनदेन नहीं हो जाता प्रतिबद्ध है, जो थोड़ी देर बाद होता है। इसका मतलब यह है कि एक मौका है कि साइडकीक आपके प्रश्न को सहेजने के बाद उसे खोजने का प्रयास करेगा, लेकिन इससे पहले कि आप इसे करें। यह आपका रिकॉर्ड नहीं ढूंढ सकता, और यह फट जाता है।

यह समस्या इतनी आम है कि साइडकीक के पास इसके बारे में अक्सर पूछे जाने वाले प्रश्न प्रविष्टि है। और एक आसान समाधान है।

इसके बजाय after_save :

app/models/question.rb
class Question < ActiveRecord::Base
  after_save :index_for_search

  # ...
end

after_commit . का उपयोग करें :

app/models/question.rb
class Question < ActiveRecord::Base
  after_commit :index_for_search

  # ...
end

और आपकी नौकरी तब तक कतार में नहीं लगेगी जब तक कि साइडकीक आपका मॉडल नहीं देख लेता।

इसलिए, जब आप किसी पृष्ठभूमि कार्य को कतारबद्ध करते हैं या अपने द्वारा किए गए परिवर्तन के बारे में कोई अन्य प्रक्रिया बताते हैं, तो after_commit का उपयोग करें . अगर आप ऐसा नहीं करते हैं, तो हो सकता है कि वे आपके द्वारा अभी-अभी छुआ गया रिकॉर्ड न ढूंढ पाएं।

लेकिन एक और समस्या है...

ठीक है, आपने अपने after_save . का एक गुच्छा बदल दिया है उपयोग करने के लिए हुक after_commit बजाय। सब कुछ काम करने लगता है। यह सब जांचने और घर जाने का समय है, है ना?

सबसे पहले, आप अपने परीक्षण चलाना चाहेंगे:

test/models/question_test.rb
require 'test_helper'

class QuestionTest < ActiveSupport::TestCase
  test "A saved question is queued for indexing" do
    assert_enqueued_with(job: QuestionIndexerJob) do
      Question.create(title: "Is it legal to kill a zombie?")
    end
  end
end
  1) Failure:
QuestionTest#test_A_saved_question_is_queued_for_indexing [/Users/jweiss/Source/testapps/after_commit/test/models/question_test.rb:7]:
No enqueued job found with {:job=>QuestionIndexerJob}

ओह! क्या परीक्षण को कार्य के लिए कतारबद्ध नहीं करना चाहिए था? वहां अभी क्या हुआ?

डिफ़ॉल्ट रूप से, रेल प्रत्येक टेस्ट केस को अपने डेटाबेस लेनदेन में लपेटता है। यह वास्तव में चीजों को गति दे सकता है। परीक्षण के दौरान आपके द्वारा किए गए सभी परिवर्तनों को पूर्ववत करने के लिए केवल एक डेटाबेस कमांड की आवश्यकता होती है।

लेकिन इसका मतलब यह भी है कि आपका after_commit कॉलबैक नहीं चलेगा। क्योंकि after_commit कॉलबैक केवल तभी चलते हैं जब सबसे बाहरी लेन-देन किया गया है।

जब आप save . को कॉल करते हैं एक परीक्षण मामले के अंदर, यह अभी भी एक लेनदेन (अधिक या कम) करता है, लेकिन यह दूसरा-सबसे-बाहरी है अब लेनदेन। तो आपका after_commit जब आप उनसे अपेक्षा करते हैं तो कॉलबैक नहीं चलेंगे। और आप परीक्षण नहीं कर सकते कि उनके अंदर क्या होता है।

इस समस्या का एक आसान समाधान भी है। test_after_commit शामिल करें आपके जेमफाइल में मणि:

Gemfile
group :test do
  gem "test_after_commit"
end

और आपका after_commit आपके सेकेंड-टू-लास्ट . के बाद हुक चलेंगे लेन-देन करता है। वही हुआ जो आप होने की उम्मीद कर रहे थे।

आप सोच रहे होंगे, "यह अजीब है। रेल के साथ आने वाले कॉलबैक का परीक्षण करने के लिए मुझे एक अलग मणि का उपयोग क्यों करना है? क्या यह अपने आप नहीं हो जाना चाहिए?"

तुम सही कह रही हो। यह अजीब है। लेकिन यह लंबे समय तक अजीब नहीं रहेगा।

एक बार रेल 5 जहाज, आपको test_after_commit . के बारे में चिंता करने की आवश्यकता नहीं होगी . क्योंकि इस समस्या को लगभग एक महीने पहले रेल में ठीक कर दिया गया था।

अपने कोड में, मैं after_commit . का उपयोग करता हूं बहुत। after_save . की तुलना में शायद मैं इसका अधिक उपयोग करता हूं ! लेकिन यह अपनी समस्याओं और अजीब किनारे के मामलों के बिना नहीं आया है।

संस्करण दर संस्करण, हालांकि, यह बेहतर होता जा रहा है। और जब आप after_commit . का उपयोग करते हैं सही जगहों पर, बहुत सारे अजीब, यादृच्छिक अपवाद अब और नहीं होंगे।


  1. बायबग, रेल और पाउ ​​के साथ रिमोट डिबगिंग

    यदि आपने पहले बायबग नहीं देखा है, तो मेरा सुझाव है कि आप इसे देखें। रूबी 2.x के लिए यह एक अच्छा डीबगर है। इसके लेखकों के शब्दों में: Byebug रूबी 2 के लिए उपयोग करने के लिए एक आसान, सुविधा संपन्न डिबगर है। यह निष्पादन नियंत्रण के लिए नए TracePoint API और कॉल स्टैक नेविगेशन के लिए नए डीबग इंस्पेक्टर A

  1. Vue, Vuex और Rails के साथ एक पूर्ण-स्टैक एप्लिकेशन का निर्माण

    स्केलेबिलिटी को ध्यान में रखते हुए फुल-स्टैक एप्लिकेशन बनाना डराने वाला हो सकता है, खासकर जब Vue और Vuex के नवीनतम संस्करण के साथ निर्माण किया जाता है, जिसमें पूर्ण टाइपस्क्रिप्ट समर्थन होता है। यह लेख अपने पाठकों को वह सब कुछ सिखाएगा जो उन्हें राज्य प्रबंधन से Vuex 4.0 के साथ स्केलेबल फुल-स्टैक एप्

  1. Chrome और Edge पर RESULT_CODE_HUNG ठीक करें

    हालाँकि इंटरनेट डोमेन में कई ब्राउज़रों का गढ़ है, लेकिन Google Chrome और Microsoft Edge सूची में सबसे ऊपर हैं। क्रोम दुनिया भर में लाखों उपयोगकर्ताओं के लिए पसंदीदा विकल्प है, जबकि एज को मेरे कई विंडोज उपयोगकर्ताओं को पसंद किया जाता है। फिर भी इन उत्कृष्ट ब्राउज़रों में कुछ खामियां भी हैं। इंटरनेट