Skip to content

feat: Enhance sample app with pause/resume and runtime backoff updates - #8

Merged
bosankus merged 5 commits into
mainfrom
bugfix/fix_build_and_logic_issue
Sep 6, 2025
Merged

bosankus merged 5 commits into
mainfrom
bugfix/fix_build_and_logic_issue

Conversation

@bosankus

@bosankus bosankus commented Sep 5, 2025 •

Copy link
Copy Markdown
Owner

feat: Enhance sample app with pause/resume and runtime backoff updates

Summary

This PR introduces major enhancements to both the sample application and the core PollingEngine. Key improvements include pause/resume capabilities, runtime backoff policy updates, improved UI/UX, new lifecycle management APIs, and refined build/publish workflows.


What's Changed

Sample App (App.kt)

  • Pause/Resume Functionality
    • The "Start Polling" button toggles to "Pause"/"Resume" based on state
    • Supports pausing/resuming polling with timer updates
  • Stop Button
    • New "Stop" button to cancel polling
  • Runtime Backoff Updates
    • "Apply Backoff" button for updating BackoffPolicy live
    • Dynamic backoff takes effect immediately
  • UI Improvements
    • Smoother log animation with AnimatedVisibility
    • Efficient log rendering using key
    • Uses pollingConfig { ... } DSL builder

PollingEngine (PollingEngine.kt)

  • Pause/Resume API
    • pause(id: String) and resume(id: String) added
  • Dynamic Backoff Update
    • updateBackoff(id: String, newPolicy: BackoffPolicy) enables live updates
  • Lifecycle Management
    • cancelAll(), shutdown() for resource management
  • Sequential Polling
    • compose(vararg configs: PollingConfig<T>) utility
  • Internal State Improvements
    • Tracks Running/Paused state per poll

Build & Configuration

  • Publishing Script (publishing.gradle.kts)
    • Centralized Maven publishing/signing configs
    • Signing supports environment variables or Gradle properties
    • Uses Vanniktech plugin for metadata
  • Version Catalog Updates
    • Added pollingengine, kotlinx-coroutines, multiple plugins
  • Gradle Files
    • Group/version/source improvements; streamlined plugin usage
    • Android library variants now managed via plugin
  • Project Structure
    • :docs as subproject; minimal docs build
    • Improved repository/project settings for Maven and local dev

Documentation & Metadata

  • Archived old CI docs, updated author info
  • Removed legacy sample files and checklists
  • Updated podspec, settings, and added helper task to docs build

PollingConfig Enhancements

  • Expanded builder DSL, improved logging/type safety
  • Timings shown in seconds to improve clarity

UI & Functional Improvements

  • Cleaner and more organized app properties UI
  • More detailed/precise timing data in log output
  • Accurate onAttempt notifications with both base and actual delay metrics

Review Checklist

  • Sample app pause/resume and stop work as described
  • Dynamic backoff changes correctly reflected in active polls
  • UI/UX improvements verified in sample app
  • Maven publishing and signing tested with both property/env configs
  • Logging, outcome descriptions, and polling callbacks produce correct data
  • Legacy files and artifacts have been cleanly removed

Testing & Notes

Please verify behaviors across Android/iOS environments for pause/resume, runtime config updates, and poll lifecycle edge cases. Confirm publishing, signing, and binary compatibility against relevant repositories. See commit for complete file-level changes.


This commit significantly revamps the sample Compose Multiplatform application to provide an interactive "Polling Terminal" experience.

**Key changes:**

*   **Interactive UI:**
    *   Replaced the basic demo with a terminal-like interface (`TerminalLog`) that displays real-time polling logs.
    *   Added an expandable "Properties" card (`PropertiesCard`) allowing users to dynamically configure `BackoffPolicy` parameters (initial delay, max delay, multiplier, jitter, max attempts, overall timeout, per-attempt timeout) via `OutlinedTextField`s.
    *   Introduced a "Start Polling" button (`GlowingButton`) to initiate the polling process with the configured properties.
    *   Displays a countdown timer for the `overallTimeoutMs`.
*   **Dynamic Polling Configuration:**
    *   The `PollingEngine` is now configured at runtime based on user input from the properties panel.
    *   Input validation is performed before starting the poll.
    *   The sample polling logic now simulates success on the 8th attempt to demonstrate exponential backoff logging.
*   **Logging and Feedback:**
    *   Detailed logging of polling attempts, results (`describeResult`), and final outcomes (`describeOutcome`) in the terminal.
    *   Log entries are styled (`LogEntryCard`) based on type (info, error, done).
    *   Improved visual feedback for running state and remaining time.
*   **Theming and Styling:**
    *   Implemented a custom dark theme (`darkScheme`) with neon accents and a specific background color.
    *   Applied a custom sans-serif font family (`buildTechTypography`) to the MaterialTheme.
*   **Android Specific Changes:**
    *   `MainActivity` now enables edge-to-edge display and enters immersive mode, hiding system bars.
*   **iOS Specific Changes:**
    *   Added `MainViewController.kt` to provide the `ComposeUIViewController` for the iOS app.
*   **Default BackoffPolicy Update:**
    *   In `BackoffPolicies.kt`, the `DEFAULT` policy now has `perAttemptTimeoutMs` set to 10000 (previously null).

**Functionality:**

*   The sample app now serves as a more comprehensive demonstration of the `PollingEngine`'s capabilities.
*   Users can experiment with different `BackoffPolicy` settings and observe their impact on the polling behavior through the live log.
*   The UI provides clear feedback on the polling process, including individual attempts, results, and overall completion status.
This commit enhances the sample Compose Multiplatform application and the core `PollingEngine` logging.

**Key Changes:**

*   **Sample App UI (`App.kt`):**
    *   The `PropertiesCard` now uses `Surface` for better elevation and visual separation, with a rounded corner shape and border.
    *   Improved layout within `PropertiesCard` using `Arrangement.spacedBy` for more consistent spacing.
    *   Added category labels ("Delays & Attempts", "Backoff & Timeouts") within `PropertiesCard` for better organization of input fields.
    *   Elapsed time in outcome descriptions (`describeOutcome`) is now displayed in seconds (e.g., "elapsedSec=1.2") instead of milliseconds for better readability.
    *   Log messages for `onComplete` now also display duration in seconds.
    *   The `onAttempt` log message now includes both the calculated base delay (before jitter) and the actual delay (after jitter and overall timeout constraints) for the upcoming attempt, both in seconds. This provides clearer insight into how backoff and jitter affect timing.
*   **PollingEngine (`PollingEngine.kt`):**
    *   Refined the timing of `onAttempt` and `metrics.recordAttempt` calls. These callbacks are now invoked just before the `delay()` call for subsequent attempts (attempt > 1), providing the *actual* sleep duration. For the first attempt, they are called immediately with a delay of 0.
    *   Removed `suspend` keyword from `cancel(id: String)` and `cancel(handle: Handle)` as they were simple map lookups and job cancellations which are internally suspendable if needed but the functions themselves don't require suspension.
*   **Removed Unused Files:**
    *   Deleted `PollingSamples.kt` as its functionality is now incorporated and expanded within the interactive `App.kt`.
    *   Deleted `Greeting.kt` as it was a placeholder.
    *   Deleted `Platform.kt` and its Android/iOS implementations (`Platform.android.kt`, `Platform.ios.kt`) as they were not being used in the sample app's current context.

**Functionality Improvements:**

*   The sample app's "Properties" section is visually cleaner and better organized.
*   Log output in the terminal provides more precise and understandable timing information for polling attempts, including the distinction between calculated base delay and the actual delay experienced.
*   The `PollingEngine`'s `onAttempt` callback now more accurately reflects the delay *about to be applied* for upcoming attempts, rather than a pre-calculated one.
This commit introduces a new GitHub Actions workflow (`.github/workflows/publish.yml`) to automate the publishing of the SDK.

**Workflow Details:**

*   **Trigger:** The workflow is triggered on pushes to the `main` branch.
*   **Runner:** It runs on `macos-latest`.
*   **Steps:**
    1.  **Checkout:** Checks out the repository code using `actions/checkout@v4`.
    2.  **Set up JDK:** Sets up Java Development Kit (JDK) version 17 (Temurin distribution) using `actions/setup-java@v4`.
    3.  **Set up Gradle:** Configures Gradle using `gradle/gradle-build-action@v3`.
    4.  **Publish Android SDK:** Executes `./gradlew :pollingengine:publish` to publish the Android library to Maven.
    5.  **Publish iOS SDK:** Executes `./gradlew :pollingengine:publishToMavenLocal` as a placeholder for publishing the iOS SDK (intended for CocoaPods).

**Functionality:**

*   Automates the build and deployment process for the Android SDK.
*   Includes a step for iOS SDK publication, currently publishing to Maven Local, which can be adapted for CocoaPods or other distribution methods.
@bosankus bosankus self-assigned this Sep 5, 2025
@bosankus bosankus changed the title Bugfix/fix build and logic issue Bugfix: fix build and logic issue Sep 6, 2025
@bosankus bosankus changed the title Bugfix: fix build and logic issue feat: Enhance sample app with pause/resume and runtime backoff updates Sep 6, 2025
bosankustellantis and others added 2 commits September 6, 2025 13:08
This commit introduces several enhancements to the sample application and the `PollingEngine` core:

**Sample App (`App.kt`):**

*   **Pause/Resume Functionality:**
    *   The "Start Polling" button now dynamically changes to "Pause" or "Resume" based on the polling state.
    *   Users can pause an ongoing polling process and resume it later.
    *   The countdown timer also reflects the paused state.
*   **Stop Button:**
    *   Added a "Stop" button to explicitly cancel an ongoing polling operation.
*   **Runtime Backoff Policy Update:**
    *   Added an "Apply Backoff" button in the properties section.
    *   Users can modify `BackoffPolicy` parameters (initial delay, max delay, etc.) while a poll is running and apply them dynamically.
    *   The `PollingEngine` will use the new policy for subsequent retry calculations.
*   **Minor UI Improvements:**
    *   Log entries in `TerminalLog` now use `key` for better performance with `AnimatedVisibility` when items are added.
    *   `AnimatedVisibility` is used for log entries for a smoother appearance.
    *   The `PollingConfig` is now created using the `pollingConfig { ... }` DSL builder.

**PollingEngine (`PollingEngine.kt`):**

*   **Pause/Resume API:**
    *   `pause(id: String)`: Pauses the polling operation identified by `id`.
    *   `resume(id: String)`: Resumes a paused polling operation.
    *   Internal `Control` data class manages the state (Running/Paused) and dynamic backoff policy for each poll.
*   **Runtime Backoff Update API:**
    *   `updateBackoff(id: String, newPolicy: BackoffPolicy)`: Allows changing the `BackoffPolicy` for an active poll at runtime. The engine will use the new policy for subsequent delay calculations and max attempts checks.
*   **Lifecycle Management:**
    *   `cancelAll()`: Cancels all currently active polling operations.
    *   `shutdown()`: Cancels all polls, shuts down the internal CoroutineScope, and prevents new polls from starting. This is useful for cleaning up resources when the engine is no longer needed.
*   **Sequential Polling (`compose`):**
    *   `compose(vararg configs: PollingConfig<T>)`: A new utility function to execute multiple `PollingConfig` instances sequentially. It stops early if any poll results in a non-success outcome and returns the outcome of the last executed poll (or the first non-success).
*   **Internal State Management:**
    *   Introduced `PollingEngine.State` enum (`Running`, `Paused`).
    *   The engine now uses an internal `controls` map to manage the state and dynamic backoff for each active poll.
    *   Polling loop now checks and respects the `Paused` state, suspending execution until resumed.
    *   Polling loop now dynamically reads the `BackoffPolicy` from the `Control` object for each iteration, allowing runtime updates.

**Build & Configuration:**

*   **Publishing Script (`publishing.gradle.kts`):**
    *   A new `publishing.gradle.kts` script is added to the `pollingengine` module to centralize Maven publishing and signing configuration, decluttering the main `build.gradle.kts`.
    *   Signing is now more robustly detected and enabled based on Gradle properties or environment variables (`signing.enabled`, `SIGNING_ENABLED`).
    *   Supports both in-memory PGP key and secret key ring file for signing.
    *   POM metadata is configured dynamically via the Vanniktech Maven Publish plugin.
*   **Gradle Version Catalog (`libs.versions.toml`):**
    *   Added `pollingengine` library version.
    *   Added `kotlinx-coroutines` version.
    *   Added plugins for `vanniktechMavenPublish`, `dokka`, `detekt`, `ktlint`, and `binaryCompatibilityValidator`.
*   **`pollingengine/build.gradle.kts`:**
    *   Updated `group` to `io.github.bosankus`.
    *   Version is now sourced from `libs.versions.pollingengine`.
    *   CocoaPods metadata (`summary`, `homepage`, `license`, `authors`) is now read from project properties.
    *   Applied `publishing.gradle.kts`.
    *   Removed direct `maven-publish` and `signing` plugin applications and configurations as they are handled by the Vanniktech plugin and the new publishing script.
    *   Android library variants for publishing are handled by the Vanniktech plugin.
*   **`composeApp/build.gradle.kts`:**
    *   Enabled `isMinifyEnabled = true` for release builds.
    *   Uses library `kotlinx.coroutines.core` from the version catalog.
    *   Dependency on `:pollingengine` is added directly in the `dependencies` block (previously also in `commonMain.dependencies`).
*   **Root `build.gradle.kts`:**
    *   Removed `io.github.gradle-nexus.publish-plugin` and its configuration.
    *   Uses `binaryCompatibilityValidator` plugin alias from the version catalog.
*   **Docs CI Setup (`docs/ci-setup.md`):**
    *   Marked the document as [ARCHIVED] as CI/publishing workflows were removed.
    *   Updated references from Sonatype/OSSRH to Maven Central Portal credentials.
*   **Podspec (`pollingengine.podspec`):**
    *   Updated author email.
*   **Settings (`settings.gradle.kts`):**
    *   Added `mavenCentral()` to `pluginManagement.repositories`.
    *   Added `mavenLocal()` to `dependencyResolutionManagement.repositories`.
    *   Included `:docs` as a subproject.
*   **New Docs Module (`docs/build.gradle.kts`):**
    *   Added a minimal Gradle build file for the `docs/` directory to allow Gradle commands from there without errors, and includes a helper `docsInfo` task.
*   **Removed Task List (`docs/tasks.md`):**
    *   Deleted the tasks checklist file.

**PollingConfig Enhancements:**

*   `PollingConfigBuilder.kt`: Added methods for `throwableMapper`, `logger`, and `metrics`.
*   `pollingConfig { ... }` DSL: A new top-level function to easily create `PollingConfig` instances using a builder lambda.
*   `PollingConfig.kt`: The `onComplete` callback now correctly type its `outcome` parameter as `PollingOutcome<T>` instead of `PollingOutcome<out T>`.
@bosankus
bosankus merged commit adaee50 into main Sep 6, 2025
2 of 6 checks passed
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.

2 participants