Skip to content

Add analytics for payments cancelled due to polling timeout#13183

Draft
cttsai-stripe wants to merge 6 commits into
masterfrom
cttsai/polling-timeout-analytics
Draft

Add analytics for payments cancelled due to polling timeout#13183
cttsai-stripe wants to merge 6 commits into
masterfrom
cttsai/polling-timeout-analytics

Conversation

@cttsai-stripe

Copy link
Copy Markdown
Contributor

Summary

  • Adds a POLLING_TIMEOUT_CANCELLATION analytics event that fires when the SDK cancels a payment because the polling budget was exceeded
  • Includes time_limit_seconds and last_known_status as additional params for investigation
  • Wires up ErrorReporter in the polling DI graph

Motivation

RUN_MOBILESDK-5413 — incident remediation to improve detection of payments cancelled due to polling timeout.

Test plan

  • Added unit test verifying analytics event fires on timeout
  • Added unit test verifying no event fires when payment succeeds after timeout
  • Existing PollingViewModelTest and PollingActivityTest pass

🤖 Generated with Claude Code

cttsai-stripe and others added 5 commits June 1, 2026 15:18
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Committed-By-Agent: claude
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Committed-By-Agent: claude
Replaces time_limit_seconds with payment_method_type for easier slicing
in incident investigation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Committed-By-Agent: claude
Follows the documented component.flow.error pattern from the
Error Analytics Trailhead doc.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Committed-By-Agent: claude
@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Diffuse output:

OLD: paymentsheet-example-release-master.apk (signature: V1, V2)
NEW: paymentsheet-example-release-pr.apk (signature: V1, V2)

          │            compressed            │           uncompressed           
          ├───────────┬───────────┬──────────┼───────────┬───────────┬──────────
 APK      │ old       │ new       │ diff     │ old       │ new       │ diff     
──────────┼───────────┼───────────┼──────────┼───────────┼───────────┼──────────
      dex │   4.6 MiB │   4.6 MiB │    -39 B │   9.7 MiB │   9.7 MiB │   +188 B 
     arsc │   3.8 MiB │   3.8 MiB │      0 B │   3.8 MiB │   3.8 MiB │      0 B 
 manifest │   5.8 KiB │   5.8 KiB │      0 B │  30.8 KiB │  30.8 KiB │      0 B 
      res │     1 MiB │     1 MiB │      0 B │   1.7 MiB │   1.7 MiB │      0 B 
   native │   2.7 MiB │   2.7 MiB │      0 B │   2.7 MiB │   2.7 MiB │      0 B 
    asset │  24.9 KiB │  23.5 KiB │ -1.5 KiB │  45.7 KiB │  44.2 KiB │ -1.5 KiB 
    other │ 245.4 KiB │ 245.4 KiB │    -14 B │ 505.1 KiB │ 505.1 KiB │      0 B 
──────────┼───────────┼───────────┼──────────┼───────────┼───────────┼──────────
    total │  12.3 MiB │  12.3 MiB │ -1.5 KiB │  18.4 MiB │  18.4 MiB │ -1.3 KiB 

 DEX     │ old   │ new   │ diff         
─────────┼───────┼───────┼──────────────
   files │     1 │     1 │  0           
 strings │ 45270 │ 45272 │ +2 (+7 -5)   
   types │ 14267 │ 14266 │ -1 (+0 -1)   
 classes │ 11589 │ 11588 │ -1 (+0 -1)   
 methods │ 63363 │ 63360 │ -3 (+14 -17) 
  fields │ 41125 │ 41126 │ +1 (+16 -15) 

 ARSC    │ old  │ new  │ diff 
─────────┼──────┼──────┼──────
 configs │  319 │  319 │  0   
 entries │ 7476 │ 7476 │  0
APK
     compressed      │     uncompressed     │                                
──────────┬──────────┼───────────┬──────────┤                                
 size     │ diff     │ size      │ diff     │ path                           
──────────┼──────────┼───────────┼──────────┼────────────────────────────────
  7.4 KiB │ -1.5 KiB │   7.3 KiB │ -1.5 KiB │ ∆ assets/dexopt/baseline.prof  
  4.6 MiB │    -39 B │   9.7 MiB │   +188 B │ ∆ classes.dex                  
 58.9 KiB │     -9 B │ 130.6 KiB │      0 B │ ∆ META-INF/CERT.SF             
 55.6 KiB │     -4 B │ 130.6 KiB │      0 B │ ∆ META-INF/MANIFEST.MF         
  1.2 KiB │     +1 B │     1 KiB │     +1 B │ ∆ assets/dexopt/baseline.profm 
  1.2 KiB │     -1 B │   1.2 KiB │      0 B │ ∆ META-INF/CERT.RSA            
──────────┼──────────┼───────────┼──────────┼────────────────────────────────
  4.7 MiB │ -1.5 KiB │    10 MiB │ -1.3 KiB │ (total)
DEX
STRINGS:

   old   │ new   │ diff       
  ───────┼───────┼────────────
   45270 │ 45272 │ +2 (+7 -5) 
  
  + POLLING_TIMED_OUT
  + VLJJILLL
  + VLLIIILLL
  + last_known_status
  + paymentsheet.polling.timed_out
  + r8-map-id-cb7067e458c12f2d7532467d1abd522e17178633b48a22142799b3b7fcfd9c13
  + ~~R8{"backend":"dex","compilation-mode":"release","has-checksums":false,"min-api":23,"pg-map-id":"cb7067e458c12f2d7532467d1abd522e17178633b48a22142799b3b7fcfd9c13","r8-mode":"full","version":"8.13.19"}
  
  - Ltk/s;
  - VLJJILL
  - VLLIIILL
  - r8-map-id-961502ca3b3b63fc968a67fe0337b09d4d17db05dbe2de9c66fbb3f6cab69470
  - ~~R8{"backend":"dex","compilation-mode":"release","has-checksums":false,"min-api":23,"pg-map-id":"961502ca3b3b63fc968a67fe0337b09d4d17db05dbe2de9c66fbb3f6cab69470","r8-mode":"full","version":"8.13.19"}
  

TYPES:

   old   │ new   │ diff       
  ───────┼───────┼────────────
   14267 │ 14266 │ -1 (+0 -1) 
  
  - Ltk/s;
  

METHODS:

   old   │ new   │ diff         
  ───────┼───────┼──────────────
   63363 │ 63360 │ -3 (+14 -17) 
  
  + bi.u0 <init>(p)
  + tk.a d(p, s, r, int)
  + tk.f <init>(String, Integer, int, int, int, String, String, String)
  + tk.k <init>(long, p, Continuation)
  + tk.k <init>(p, long, Continuation)
  + tk.l <init>(p, Continuation, int)
  + tk.m <init>(String, long, long, int, String, String, String)
  + tk.n <init>(p, c)
  + tk.p <init>(m, f3, b, a1, f)
  + tk.p h(p, c) → Object
  + tk.p i()
  + tk.q <init>(a, int)
  + tk.q onClick(View)
  + tk.r <clinit>()
  
  - bi.u0 <init>(q)
  - tk.a d(q, s, r, int)
  - tk.f <init>(String, Integer, int, int, int, String, String)
  - tk.k <init>(long, q, Continuation)
  - tk.k <init>(q, long, Continuation)
  - tk.l <init>(q, Continuation, int)
  - tk.m <init>(String, long, long, int, String, String)
  - tk.n <init>(q, c)
  - tk.p <init>(q, c)
  - tk.p p(Object) → Object
  - tk.q <init>(m, f3, b, a1)
  - tk.q h(q, c) → Object
  - tk.q i()
  - tk.q j(c) → Object
  - tk.r <init>(a, int)
  - tk.r onClick(View)
  - tk.s <clinit>()
  

FIELDS:

   old   │ new   │ diff         
  ───────┼───────┼──────────────
   41125 │ 41126 │ +1 (+16 -15) 
  
  + bj.c M: c
  + bj.c N: c[]
  + tk.f l: String
  + tk.k l: p
  + tk.l k: p
  + tk.m g: String
  + tk.n i: p
  + tk.p f: m
  + tk.p g: f3
  + tk.p h: f
  + tk.p i: x0
  + tk.p j: x0
  + tk.q e: int
  + tk.q f: a
  + tk.r a: float
  + tk.r b: float
  
  - bj.c M: c[]
  - tk.k l: q
  - tk.l k: q
  - tk.n i: q
  - tk.p h: Object
  - tk.p i: q
  - tk.p j: int
  - tk.q f: m
  - tk.q g: f3
  - tk.q h: x0
  - tk.q i: x0
  - tk.r e: int
  - tk.r f: a
  - tk.s a: float
  - tk.s b: float

@cttsai-stripe cttsai-stripe marked this pull request as ready for review June 3, 2026 00:14
@cttsai-stripe cttsai-stripe requested review from a team as code owners June 3, 2026 00:14
@tjclawson-stripe

Copy link
Copy Markdown
Collaborator

Most of the PMs poll here so we need to fire this event here as well

ctaText = R.string.stripe_blik_confirm_payment,
stripeAccountId = requestOptions.stripeAccount,
qrCodeUrl = null,
paymentMethodType = PaymentMethod.Type.Blik.code,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we use actionable.paymentMethod?.type here (and below) instead of hardcoding this. If we added a new PM that also used this branch, then this would become incorrect

Comment on lines -127 to -130
performOneOffPoll()
}

private suspend fun performOneOffPoll() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did the performOneOffPoll function get removed here?

@amk-stripe

Copy link
Copy Markdown
Collaborator

Most of the PMs poll here so we need to fire this event here as well

If we need to send this event from multiple places, we may not want to use errorReporter. Using an event reporter can enforce that we send the same params for an analytic event no matter where we trigger it from, vs. errorReporter we'd probably end up duplicating our params logic in two places

@cttsai-stripe cttsai-stripe marked this pull request as draft June 5, 2026 23:21
Addresses review feedback: use a typed event reporter interface instead
of ErrorReporter to enforce consistent params across both polling sites
(PollingViewModel and PaymentFlowResultProcessor). Also uses dynamic
paymentMethod type instead of hardcoding in PollingNextActionHandler.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Committed-By-Agent: claude
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants