Skip to content

Micro Runtime Cleanup 3: Add service lastError() and centralize runtime error recording #73

Open

Description

@matkomat

Parent issue: #42

Summary

Service runtime failures need a first-class PHP-visible path. Before layering on reset/stop/control-subject work, the service should have one consistent way to record errors and expose them to callers.

Goal

Introduce Service::lastError() and a single internal recordError() path that all runtime failures can use without breaking cleanup or reply flow.

Scope

  • src/Micro/Service.php
  • src/Micro/ServiceInterface.php
  • tests/Integration/Micro/ServiceTest.php
  • tests/Integration/Micro/StatsHandlerTest.php only if shared helpers/assertions need updating

Deliverables

  • lastError(): ?\Throwable on the service API
  • centralized runtime error recording inside Service
  • throwing user errorHandler callbacks cannot break the main error path
  • response-send failures become observable from the service layer

Out of scope

  • duplicate-reply suppression details
  • graceful stop/drain refactor
  • docs refresh

Acceptance criteria

  • handler exceptions update lastError() and endpoint stats
  • response-send failures update lastError()
  • a throwing errorHandler does not swallow the original runtime failure or break cleanup/reply flow
  • integration coverage exists for the above behavior

Parallelism

Can start immediately.
Blocks reset semantics, control-subject hardening, and graceful stop/drain work because those paths should all use the same error-recording helper.

Activity

  1. matkomat commented on Mar 31, 2026

    @matkomat
    ContributorAuthor

    Implementation plan for whoever picks this up:

    Goal

    • Add first-class service runtime error visibility through Service::lastError().
    • Introduce one internal recordError() path inside the micro service layer.
    • Keep this issue narrowly scoped to error recording and observability.
    • Start from main, not from PR fix: tighten micro service semantics #70 or any follow-up branch.

    Target API after this issue

    Public service API should gain:

    • ServiceInterface::lastError(): ?\Throwable
    • Service::lastError(): ?\Throwable

    Internal service behavior should gain:

    • a private ?\Throwable $lastError field in Service
    • a private recordError(\Throwable $e): void helper that:
      • stores the latest error on the service
      • invokes the configured errorHandler, if present
      • swallows exceptions thrown by the user-provided errorHandler

    Scope

    Touch only what is needed for this issue:

    • src/Micro/Service.php
    • src/Micro/ServiceInterface.php
    • tests/Integration/Micro/ServiceTest.php
    • tests/Integration/Micro/StatsHandlerTest.php only if needed for shared assertions or compile fallout

    What should change in Service behavior

    1. Handler exceptions
    • When an endpoint handler throws, the service should still update endpoint stats as today.
    • In addition, it should call recordError($e) so callers can inspect lastError().
    1. Response-send failures
    1. User error handlers
    • If ServiceConfig::errorHandler itself throws, that must not replace or erase the original runtime failure.
    • The original service runtime failure remains the one stored in lastError().

    Test changes

    Add or port focused integration coverage for these paths:

    • handler failure is exposed through lastError() and endpoint stats
    • a throwing user errorHandler does not break the main error flow
    • response-send failure becomes observable through lastError()

    Preferred naming direction:

    • testHandlerFailureIsExposedThroughLastErrorAndStats
    • testThrowingErrorHandlerDoesNotBreakErrorFlow
    • testResponseSendFailureIsObservable

    Do not add tests here for:

    • reset() semantics
    • control-subject callback hardening
    • graceful stop() / deferred cleanup
    • duplicate-response behavior after a successful reply

    Those belong to later issues.

    Explicit non-goals / forbidden changes

    Acceptance checklist

    • ServiceInterface exposes lastError(): ?\Throwable
    • Service stores and returns the latest runtime error
    • handler exceptions update both endpoint stats and lastError()
    • automatic error-response send failures update lastError()
    • a throwing configured errorHandler does not break the main runtime error path
    • no unrelated lifecycle or API cleanup work is folded into this PR

    Suggested verification

    • vendor/bin/phpunit tests/Integration/Micro/ServiceTest.php
    • vendor/bin/phpunit tests/Integration/Micro/StatsHandlerTest.php if touched

    Review notes

    The review for this issue will check specifically for:

    • accidental scope drift into stop(), reset(), or control-subject hardening
    • any src/Message.php edits
    • duplicate-reply logic being introduced too early
    • whether lastError() truly reflects the original runtime failure when errorHandler also throws
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:microMicro/service frameworkenhancementNew feature or requestpriority:P1High-priority parity or behavior gap

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions