Commit adaee50
feat: Enhance sample app with pause/resume and runtime backoff updates (#8)
* feat: Enhance sample app with interactive terminal and property editor
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.
* feat: Improve sample app UI and logging precision
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.
* feat: Add GitHub Actions workflow for publishing SDK
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.
* feat: Enhance sample app with pause/resume and runtime backoff updates
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>`.
---------
Co-authored-by: Ankush Bose <ankush.bose@external.stellantis.com>1 parent 8a7dc2b commit adaee50
25 files changed
Lines changed: 1176 additions & 592 deletions
File tree
- .github/workflows
- composeApp
- src
- androidMain/kotlin/in/androidplay/pollingengine
- commonMain/kotlin/in/androidplay/pollingengine
- sample
- iosMain/kotlin/in/androidplay/pollingengine
- docs
- gradle
- pollingengine
- src/commonMain/kotlin/in/androidplay/pollingengine/polling
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
0 commit comments