Decision Issue Sync - department-of-veterans-affairs/caseflow GitHub Wiki

Decision Issue Sync


Currently Decision Issue Sync (DIS) will sync a request issue attached to an End Product Establishment (EPE) with VBMS. If the attached EPE has a sync_status of CLR, then a decision issue sync gets triggered on that request issue. The sync_decision_issue! checks if the request issue is processed, submitted and ready. Then, finds the veteran attached to the EPE and starts the transaction. This creates decision issues and once the sync is completed a remand supplemental claim is created. A problem we experienced is when more than one request issue that is attached to the EPE can inadvertently be bypassed if they're being synced at the same time. This results in the remand supplemental claim not being generated.

request_issue.rb

def sync_decision_issues!
    return if processed?

    fail NotYetSubmitted unless submitted_and_ready?

    clear_error!
    attempted!

    # pre-fetch the internal veteran record before we start the transaction
    # to avoid a slow BGS call causing the transaction to timeout
    end_product_establishment.veteran
      transaction do
        return unless create_decision_issues

        end_product_establishment.on_decision_issue_sync_processed(self)
        clear_error!
        close_decided_issue!
        processed!
      end
  end

A solution for this problem, was implemented with the hlr_sync_lock. This method can be found in sync_lock.rb file and is called in RequestIssue(request_issue.rb). Within the sync_decision_issues method, hlr_sync_lock wraps around the transaction. This will create a lock key: hlr_sync_lock:#{EPE.id} in redis and this will create the sync lock with the key value pair if it doesn't already exist and an expiration time is given upon creation. Once the sync has been completed, the lock key is removed.

updated request_issue.rb with hlr_sync_lock

def sync_decision_issues!
    return if processed?

    fail NotYetSubmitted unless submitted_and_ready?

    clear_error!
    attempted!

    # pre-fetch the internal veteran record before we start the transaction
    # to avoid a slow BGS call causing the transaction to timeout
    end_product_establishment.veteran


    hlr_sync_lock do
      transaction do
        return unless create_decision_issues

        end_product_establishment.on_decision_issue_sync_processed(self)
        clear_error!
        close_decided_issue!
        processed!
      end
    end
  end

HLR_SYNC_LOCK


hlr_sync_lock will stop any other request issues associated with the current EPE from syncing with BGS concurrently if the claim is a Higher Level Review. This will ensure that the remand supplemental claim generation that occurs within on_decision_issue_sync_processed will not be inadvertently bypassed due to two request issues from the same claim being synced at the same time. If this situation does occur, one of the request issues will error out with Caseflow::Error:SyncLockFailed and be picked up to sync again later

sync_lock.rb

def hlr_sync_lock
    if decision_review.is_a?(HigherLevelReview) && block_given?
      redis = Redis.new(url: Rails.application.secrets.redis_url_cache)
      lock_key = "hlr_sync_lock:#{end_product_establishment.id}"

      begin
        # create the sync lock with a key, value pair only 
        # IF it doesn't already exist and give it an expiration time upon creation
        sync_lock_acquired = redis.set(lock_key, "lock is set", :nx => true, :ex => LOCK_TIMEOUT.to_i)

        fail Caseflow::Error::SyncLockFailed, message: "#{Time.zone.now}" unless sync_lock_acquired
        # set expire as another failsafe
        redis.expire(lock_key, LOCK_TIMEOUT.to_i)
        yield
      ensure
        redis.del(lock_key)
      end
    elsif block_given?
      yield
    end
  end