(info *session.Info, now time.Time)
| 772 | } |
| 773 | |
| 774 | func classifyRecoveredTaskSession(info *session.Info, now time.Time) (string, string) { |
| 775 | if info == nil { |
| 776 | return taskRecoveryClassificationMissing, "session metadata is unavailable" |
| 777 | } |
| 778 | if liveness := info.Liveness; liveness != nil { |
| 779 | if strings.TrimSpace(liveness.StallState) == store.SessionStallStateDetected { |
| 780 | return taskRecoveryClassificationStalled, firstTaskRecoveryDetail( |
| 781 | liveness.StallReason, |
| 782 | info.StopDetail, |
| 783 | "session liveness monitor marked the process stalled", |
| 784 | ) |
| 785 | } |
| 786 | if lastActivityAt := taskSessionLastActivityAt(liveness); lastActivityAt != nil && |
| 787 | !lastActivityAt.IsZero() && |
| 788 | now.Sub(lastActivityAt.UTC()) >= session.DefaultLivenessStallAfter && |
| 789 | taskSessionMatchesRecordedSubprocess(liveness) { |
| 790 | return taskRecoveryClassificationStalled, firstTaskRecoveryDetail( |
| 791 | liveness.StallReason, |
| 792 | store.SessionStallReasonActivityTimeout, |
| 793 | info.StopDetail, |
| 794 | ) |
| 795 | } |
| 796 | if taskSessionMatchesRecordedSubprocess(liveness) { |
| 797 | return taskRecoveryClassificationOrphaned, fmt.Sprintf( |
| 798 | "subprocess pid %d is still alive without a live daemon owner", |
| 799 | liveness.SubprocessPID, |
| 800 | ) |
| 801 | } |
| 802 | } |
| 803 | return taskRecoveryClassificationCrashed, firstTaskRecoveryDetail( |
| 804 | info.StopDetail, |
| 805 | "bound session is not live", |
| 806 | ) |
| 807 | } |
| 808 | |
| 809 | func taskSessionLastActivityAt(liveness *store.SessionLivenessMeta) *time.Time { |
| 810 | if liveness == nil { |
no test coverage detected