MCPcopy Create free account
hub / github.com/erpc/erpc / TryUpdateIfStale

Method TryUpdateIfStale

data/shared_state_variable.go:390–469  ·  view source on GitHub ↗
(ctx context.Context, staleness time.Duration, executeNewValueFn func(ctx context.Context) (int64, error))

Source from the content-addressed store, hash-verified

388}
389
390func (c *counterInt64) TryUpdateIfStale(ctx context.Context, staleness time.Duration, executeNewValueFn func(ctx context.Context) (int64, error)) (int64, error) {
391 ctx, span := common.StartSpan(ctx, "CounterInt64.TryUpdateIfStale",
392 trace.WithAttributes(
393 attribute.String("key", c.key),
394 attribute.Int64("staleness_ms", staleness.Milliseconds()),
395 ),
396 )
397 defer span.End()
398
399 if !c.IsStale(staleness) {
400 span.SetAttributes(attribute.Bool("skipped_not_stale", true))
401 return c.value.Load(), nil
402 }
403
404 // Track time waiting for mutex
405 _, mutexSpan := common.StartSpan(ctx, "CounterInt64.TryUpdateIfStale.AcquireMutex")
406 c.updateMu.Lock()
407 mutexSpan.End()
408 defer c.updateMu.Unlock()
409
410 // Double-check staleness after acquiring mutex
411 if !c.IsStale(staleness) {
412 span.SetAttributes(attribute.Bool("skipped_not_stale_after_mutex", true))
413 return c.value.Load(), nil
414 }
415
416 initialVal := c.value.Load()
417 span.SetAttributes(attribute.Int64("initial_value", initialVal))
418 // IMPORTANT: Foreground path MUST be local-only and bounded by updateMaxWait.
419 // Do NOT acquire distributed locks or do any remote I/O here, otherwise degraded shared state
420 // (e.g. Redis lock acquisition) can block normal request flow.
421 span.SetAttributes(attribute.Bool("foreground_remote_io_disabled", true))
422
423 // Execute the refresh function (e.g., RPC call to get latest block) in background
424 resultCh := make(chan refreshResult, 1)
425 go func() {
426 fnCtx, fnCancel := context.WithTimeout(c.registry.appCtx, c.registry.fallbackTimeout)
427 defer fnCancel()
428
429 // Create a span for the actual RPC/refresh call - this is usually what takes time
430 _, fnSpan := common.StartSpan(ctx, "CounterInt64.TryUpdateIfStale.ExecuteRefresh",
431 trace.WithAttributes(
432 attribute.String("key", c.key),
433 attribute.Int64("timeout_ms", c.registry.fallbackTimeout.Milliseconds()),
434 ),
435 )
436 value, err := executeNewValueFn(fnCtx)
437 if err != nil {
438 fnSpan.SetAttributes(attribute.String("error", err.Error()))
439 } else {
440 fnSpan.SetAttributes(attribute.Int64("result_value", value))
441 }
442 fnSpan.End()
443
444 resultCh <- refreshResult{val: value, err: err}
445 }()
446
447 timer := time.NewTimer(c.registry.updateMaxWait)

Calls 13

applyRefreshResultMethod · 0.95
markFreshAttemptMethod · 0.95
continueAsyncRefreshMethod · 0.95
StartSpanFunction · 0.92
EndMethod · 0.80
SetAttributesMethod · 0.80
LoadMethod · 0.80
IsStaleMethod · 0.65
LockMethod · 0.65
UnlockMethod · 0.65
ErrorMethod · 0.65
StringMethod · 0.45