Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automate fix for RedistributedCase::CannotRedistribute Sentry alert #14705

Closed
2 tasks
yoomlam opened this issue Jul 16, 2020 · 2 comments · Fixed by #15248
Closed
2 tasks

Automate fix for RedistributedCase::CannotRedistribute Sentry alert #14705

yoomlam opened this issue Jul 16, 2020 · 2 comments · Fixed by #15248
Assignees
Labels
Priority: Medium Blocking issue w/workaround, or "second in" priority for new work. Product: caseflow-queue Source: Sentry Alert created because of a Sentry alert Team: Echo 🐬

Comments

@yoomlam
Copy link
Contributor

yoomlam commented Jul 16, 2020

Description

So far, Bat Team is responsible for fixing appeals that need to be redistributed when prompted by RedistributedCase::CannotRedistribute Sentry alerts. We should automate the fix so that appeals are not stuck/delayed.

The fix is described here, and Hunter provided a snippet to fix several at a time:

vacols_ids=%w"0000000 1111111 2222222 3333333"
vacols_ids.size

appeals = vacols_ids.map { |vacols_id| LegacyAppeal.find_by(vacols_id: vacols_id) };
appeals_with_active_tasks = appeals.select do |appeal|
  appeal.tasks.active.where.not(type: [TrackVeteranTask.name, RootTask.name]).any?
end.map(&:vacols_id);

## Fix appeals that should be distributed
appeals_without_active_tasks = vacols_ids - appeals_with_active_tasks
appeals_without_active_tasks.size

appeals_without_active_tasks.map do |vacols_id|
  DistributedCase.find_by(case_id: vacols_id).nil?
end
# Fix the appeals without active tasks
appeals_without_active_tasks.each do |vacols_id|
  DistributedCase.find_by(case_id: vacols_id).update!(case_id: "#{vacols_id}-attempt-#{Time.zone.now}")
end

# Double-check active tasks
appeals_with_active_tasks.map{|id| LegacyAppeal.find_by(vacols_id: id).treee}
appeals_with_active_tasks.map { |vacols_id| LegacyAppeal.find_by(vacols_id: vacols_id).location_code }

appeals_with_active_tasks.each do |vacols_id|
 la=LegacyAppeal.find_by(vacols_id: vacols_id)
 needs_update = la.location_code!=LegacyAppeal::LOCATION_CODES[:caseflow]
 puts (needs_update ? "Updating #{vacols_id}" : "Skipping #{vacols_id}")
 AppealRepository.update_location!(la, LegacyAppeal::LOCATION_CODES[:caseflow]) if needs_update
end

Open Questions

  1. The Bat Team instructions and snippet call for some manual inspection, is there anything done during inspection that cannot be automated?
  2. What is the impact/harm of redistributing a case without active tasks (ignoring TrackVeteranTasks)?
  3. The snippet allows redistribution of cases with on-hold tasks and not active tasks. Why does this make sense?

Caseflow should probably use a different suffix to differentiate from manual fixes that use suffix '-attempt1'.

Acceptance criteria

Background/context/resources

Also see #13596 and #14597.

Technical notes

Check for when redistribution can or cannot occur:

def ok_to_redistribute?
# redistribute if there are no relevant tasks
return true if legacy_appeal_relevant_tasks.blank?
# do not redistribute if any relevant task is open (not completed or cancelled)
return false if legacy_appeal_relevant_tasks.any?(&:open?)
# redistribute if all HearingTasks are cancelled
return true if !legacy_appeal_hearing_tasks.empty? && legacy_appeal_hearing_tasks.all?(&:cancelled?)
# be conservative; return false so that appeal is manually addressed
false
end

What Caseflow does in each scenario:

if ok_to_redistribute?
rename_existing_distributed_case!
else
alert_existing_distributed_case_not_unique
false

@yoomlam yoomlam added Product: caseflow-queue Team: Echo 🐬 Source: Sentry Alert created because of a Sentry alert Priority: Medium Blocking issue w/workaround, or "second in" priority for new work. labels Jul 16, 2020
@hschallhorn
Copy link
Contributor

what is this chart?

1 | 
2 | |||
3 | ||||||
5 | 
8 | 

Why 2?

  • Already have the code to implement from batteam wiki

Why 3?

  • Looking into what conditions it is acceptable to redistribute (as there are very few at the moment and they are very specific cases)

@yoomlam
Copy link
Contributor Author

yoomlam commented Jul 17, 2020

While we're in this part of the code, let's test using tags instead of extra for fields that we want to search for in Sentry.

In redistributed_case.rb around line 63:

  def alert_existing_distributed_case_not_unique
    error = CannotRedistribute.new("DistributedCase already exists")
    # Method 1
    Raven.tags_context judge: new_distribution.judge.css_id
    Raven.capture_exception(
      error,
      # Method 2
      tags: { vacols_id: case_id },
      extra: {...}

See these references:

va-bot pushed a commit that referenced this issue Aug 6, 2020
Resolves #13596
Relevant to #14705 

### Description
When we distribute legacy appeals, we update the location to the judge in vacols so it will appear in their queue. If there is already a distributed case for this appeal and [certain other criteria are not met](https://github.com/department-of-veterans-affairs/caseflow/blob/13b99749f8bac8b6d969f693f1d230f4fb2fa4dd/app/services/redistributed_case.rb#L26-L38), we should not distribute this appeal. HOWEVER, the location has already been updated to the judge and the case has essentially been "distributed", even though we did not create a new distributed for the appeal. This could lead to both the judge starting a decision before a hearing is held or other unwanted scenarios.

Instead, we should update the location of the case to be caseflow if there are open tasks, or send it back to distribution to be handled manually by batteam.

### Acceptance Criteria
- [x] Cases that cannot be distributed are not moved to the judge
- [x] Cases with open tasks should be in the "caseflow" location
- [x] If the location code of the case can be updated to caseflow, do not send a sentry alert
- [x] [Batteam wiki is updated to show correct fixes for these alerts](https://github.com/department-of-veterans-affairs/appeals-deployment/wiki/Bat-Team-Quick-Ref#redistributedcasecannotredistribute-sentry-alert)

### Testing Plan
1. Find an appeal ready to be distributed and give it a task that would send it back to distribution
```ruby
# What case will be distributed next?
vacols_id = VACOLS::CaseDocket.distribute_nonpriority_appeals(User.third,"not_genpop", nil, 1000, false, dry_run: true).first["bfkey"]
# Let's create a previous distribution for this case
distribution = FactoryBot.build(:distribution, judge: User.third)
distribution.save(validate: false)
distribution.distributed_cases.create(
        case_id: vacols_id,
        priority: false,
        docket: "legacy",
        ready_at: VacolsHelper.normalize_vacols_datetime(Time.zone.now),
        docket_index: "123",
        genpop: false,
        genpop_query: "any"
      )
# Now let's make sure we fail all `ok_to_redistribute?` validations
appeal = LegacyAppeal.find_or_create_by_vacols_id(vacols_id)
HearingTask.create!(appeal: appeal).completed!
appeal.reload.treee
LegacyAppeal 25 (legacy)   ID   STATUS    ASGN_BY ASGN_TO UPDATED_AT
└── HearingTask            2120 completed         Bva     2020-08-05 15:32:32 UTC
```
2. Lets see what happens when we distribute the case
```ruby
VACOLS::Case.find_by(bfkey: vacols_id).bfcurloc
=> "81"
distribution = FactoryBot.build(:distribution, judge: User.third)
distribution.save(validate: false)
LegacyDocket.new.distribute_nonpriority_appeals(distribution)
VACOLS::Case.find_by(bfkey: vacols_id).bfcurloc
=> "81"
```
3. Open a task on the appeal, indicating that it is being worked in caseflow
```ruby
HearingTask.create!(appeal: appeal)
```
4. Lets see what happens when we distribute the case
```ruby
VACOLS::Case.find_by(bfkey: vacols_id).bfcurloc
=> "81"
distribution = FactoryBot.build(:distribution, judge: User.third)
distribution.save(validate: false)
LegacyDocket.new.distribute_nonpriority_appeals(distribution)
VACOLS::Case.find_by(bfkey: vacols_id).bfcurloc
=> "CASEFLOW"
```
@hschallhorn hschallhorn added this to the PI5-S2: Edith S. Sampson milestone Aug 24, 2020
@ajspotts ajspotts self-assigned this Sep 2, 2020
va-bot pushed a commit that referenced this issue Sep 21, 2020
…15248)

Resolves #14705

### Description
This fix allows for legacy appeals that have closed actionable (non-Root or TrackVeteran tasks) to be automatically redistributed.  Prior to this, the 🦇 team would have to manually redistribute these cases when [notified](https://sentry.prod.appeals.va.gov/department-of-veterans-affairs/caseflow/issues/7524/) by the `RedistributedCase::CannotRedistribute` Sentry alert.  

### Acceptance Criteria
- [ ] Legacy appeals with closed actionable tasks are automatically redistributed

### Testing Plan
1. Find an appeal ready to be distributed and give it a task that would send it back to distribution
```ruby
# What case will be distributed next?
vacols_id = VACOLS::CaseDocket.distribute_nonpriority_appeals(User.third,"not_genpop", nil, 1000, false, dry_run: true).first["bfkey"]
# Let's create a previous distribution for this case
distribution = FactoryBot.build(:distribution, judge: User.third)
distribution.save(validate: false)
distribution.distributed_cases.create(
        case_id: vacols_id,
        priority: false,
        docket: "legacy",
        ready_at: VacolsHelper.normalize_vacols_datetime(Time.zone.now),
        docket_index: "123",
        genpop: false,
        genpop_query: "any"
      )

appeal = LegacyAppeal.find_or_create_by_vacols_id(vacols_id)
HearingTask.create!(appeal: appeal).completed!
appeal.reload.treee
LegacyAppeal 26 (legacy)   │ ID   │ STATUS    │ ASGN_BY │ ASGN_TO │ UPDATED_AT
└── HearingTask            │ 2701 │ completed │         │ Bva     │ 2020-09-15 17:35:54 UTC │
```
2. Lets see what happens when we distribute the case (make sure it is being properly redistributed)
```ruby
VACOLS::Case.find_by(bfkey: vacols_id).bfcurloc
=> "81"
distribution = FactoryBot.build(:distribution, judge: User.third)
distribution.save(validate: false)
LegacyDocket.new.distribute_nonpriority_appeals(distribution)
VACOLS::Case.find_by(bfkey: vacols_id).bfcurloc
=> "AABSHIRE"
```
3. Open a task on the appeal, indicating that it is being worked in caseflow
```ruby
HearingTask.create!(appeal: appeal)
appeal.reload.treee
LegacyAppeal 26 (legacy)  │ ID   │ STATUS    │ ASGN_BY │ ASGN_TO │ UPDATED_AT              
├── HearingTask           │ 2701 │ completed │         │ Bva     │ 2020-09-15 17:35:54 UTC │
└── HearingTask           │ 2702 │ assigned  │         │ Bva     │ 2020-09-15 17:41:25 UTC │
```
4. Lets see what happens when we distribute the case (case with active actionable task should remain in caseflow)
```ruby
VACOLS::Case.find_by(bfkey: vacols_id).update(bfcurloc: "81")
=> "81"
distribution = FactoryBot.build(:distribution, judge: User.third)
distribution.save(validate: false)
LegacyDocket.new.distribute_nonpriority_appeals(distribution)
VACOLS::Case.find_by(bfkey: vacols_id).bfcurloc
=> "CASEFLOW"
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Priority: Medium Blocking issue w/workaround, or "second in" priority for new work. Product: caseflow-queue Source: Sentry Alert created because of a Sentry alert Team: Echo 🐬
Projects
None yet
3 participants