{"id":47863915,"url":"https://github.com/yangchenlarkin/Monstra","last_synced_at":"2026-04-04T03:01:05.930Z","repository":{"id":311463234,"uuid":"1041183549","full_name":"yangchenlarkin/Monstra","owner":"yangchenlarkin","description":"High-performance Swift framework for task execution, memory caching, and data management with intelligent execution merging, TTL caching, and retry logic","archived":false,"fork":false,"pushed_at":"2025-09-09T01:03:48.000Z","size":2163,"stargazers_count":90,"open_issues_count":0,"forks_count":9,"subscribers_count":10,"default_branch":"main","last_synced_at":"2026-03-13T18:55:38.387Z","etag":null,"topics":["async-await","cache","caching","cocoapods","concurrency","data-management","execution-merging","ios","macos","memory-cache","performance","retry-logic","swift","swift-framework","swift-package-manager","task-management","ttl","tvos","watchos"],"latest_commit_sha":null,"homepage":"https://yangchenlarkin.github.io/Monstra/","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yangchenlarkin.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-08-20T05:34:18.000Z","updated_at":"2026-03-12T16:02:24.000Z","dependencies_parsed_at":"2025-08-24T20:47:35.672Z","dependency_job_id":null,"html_url":"https://github.com/yangchenlarkin/Monstra","commit_stats":null,"previous_names":["yangchenlarkin/monstra"],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/yangchenlarkin/Monstra","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yangchenlarkin%2FMonstra","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yangchenlarkin%2FMonstra/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yangchenlarkin%2FMonstra/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yangchenlarkin%2FMonstra/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yangchenlarkin","download_url":"https://codeload.github.com/yangchenlarkin/Monstra/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yangchenlarkin%2FMonstra/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31385935,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T01:22:39.193Z","status":"online","status_checked_at":"2026-04-04T02:00:07.569Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async-await","cache","caching","cocoapods","concurrency","data-management","execution-merging","ios","macos","memory-cache","performance","retry-logic","swift","swift-framework","swift-package-manager","task-management","ttl","tvos","watchos"],"created_at":"2026-04-04T00:00:29.928Z","updated_at":"2026-04-04T03:01:05.921Z","avatar_url":"https://github.com/yangchenlarkin.png","language":"Swift","funding_links":[],"categories":["Data and Storage","Libs"],"sub_categories":["Cache"],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"Logo.png\" alt=\"Monstra Logo\" width=\"50%\"\u003e\n\u003c/div\u003e\n\n[![Swift](https://img.shields.io/badge/Swift-5.5-orange.svg)](https://swift.org)\n[![Platform](https://img.shields.io/badge/platform-iOS%20%7C%20macOS%20%7C%20tvOS%20%7C%20watchOS-lightgrey.svg)](https://developer.apple.com)\n[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n[![Swift Package Manager](https://img.shields.io/badge/Swift%20Package%20Manager-compatible-brightgreen.svg)](https://github.com/apple/swift-package-manager)\n[![CocoaPods](https://img.shields.io/badge/CocoaPods-compatible-brightgreen.svg)](https://cocoapods.org)\n[![Docs](https://img.shields.io/badge/docs-API%20Reference-blue)](https://yangchenlarkin.github.io/Monstra/)\n\n**English** | [简体中文](README_CN.md)\n\nA high-performance Swift framework providing efficient task execution, memory caching, and data management utilities with intelligent execution merging, TTL caching, and retry logic.\n\nDocumentation: \u003ca href=\"https://yangchenlarkin.github.io/Monstra/\" target=\"_blank\" rel=\"noopener noreferrer\"\u003eAPI Reference (Jazzy)\u003c/a\u003e  \n\n## 🚀 Features\n\n### Monstore - Caching System\n\n#### MemoryCache\n- **⏰ TTL \u0026 Priority Support**: Advanced time-to-live functionality with automatic expiration and configurable priority-based eviction\n- **💥 Avalanche Protection**: Intelligent TTL randomization prevents cache stampede and simultaneous expiration cascades\n- **🛡️ Breakdown Protection**: Comprehensive null value caching and robust key validation for enhanced reliability\n- **📊 Statistics \u0026 Monitoring**: Built-in cache statistics, performance metrics, and real-time monitoring capabilities\n\n### Monstask - Task Execution Framework\n\n#### **MonoTask**\n\n- **🔄 Execution Merging**: Multiple concurrent requests merged into single execution\n- **⏱️ TTL Caching**: Results cached for configurable duration with automatic expiration\n- **🔄 Advanced Retry Logic**: Exponential backoff, fixed intervals, and hybrid retry strategies\n- **🎯 Manual Cache Control**: Fine-grained cache invalidation with execution strategy options\n\n#### **KVLightTasksManager**\n- **📈 Peak Shaving**: Prevents excessive task execution volume through Priority-Based Scheduling (LIFO/FIFO strategies with configurable limits)\n- **🔄 Batch Processing**: Support for single and batch data provisioning to enhance backend execution efficiency\n- **📊 Concurrent Execution**: Configurable concurrent task limits (default: 4 running, 256 queued)\n- **🎯 Execution Merging**: Intelligent request deduplication and merging to prevent duplicate work and optimize resource usage\n- **💾 Result Caching**: Integrated MemoryCache for optimized performance\n\n#### **KVHeavyTasksManager**\n- **📊 Progress Tracking**: Real-time progress updates with custom event publishing and broadcasting capabilities\n- **🎯 Priority-Based Scheduling**: Advanced LIFO/FIFO strategies with intelligent interruption support\n- **🔄 Task Lifecycle Management**: Complete start/stop/resume functionality with provider state preservation\n- **📱 Concurrent Control**: Optimized concurrent execution limits (default: 2 running, 64 queued)\n- **🎯 Execution Merging**: Intelligent request deduplication and merging to prevent duplicate work and optimize resource usage\n- **💾 Result Caching**: Integrated MemoryCache for enhanced performance and efficiency\n\n## 🚀 Quick Start\n\n### Installation\n\n#### Swift Package Manager (Recommended)\n\nAdd Monstra to your `Package.swift`:\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/yangchenlarkin/Monstra.git\", from: \"0.1.0\")\n]\n```\n\nOr add it directly in Xcode:\n1. File → Add Package Dependencies\n2. Enter the repository URL: `https://github.com/yangchenlarkin/Monstra.git`\n3. Select the version you want to use\n\n#### CocoaPods\n\nAdd Monstra to your `Podfile`:\n\n```ruby\npod 'Monstra', '~\u003e 0.1.0'\n```\n\n**Note**: Monstra is published as a unified framework, so you get all components together.\n\n## 🎯 When to Use Each Component\n\n| Component | Best For | Key Features |\n|-----------|----------|-------------|\n| **MonoTask** | Single expensive operations | Execution merging, TTL caching, retry logic |\n| **KVLightTasksManager** | Fast, lightweight operations | Batch processing, key validation, high throughput |\n| **KVHeavyTasksManager** | Resource-intensive operations | Progress tracking, lifecycle management, error recovery |\n\n#### **Some Scenarios for Each Component**\n\n- **MonoTask**: API calls, database queries, expensive computations that benefit from caching and deduplication\n- **KVLightTasksManager**: User profile fetching, search results, configuration loading, high-frequency operations\n- **KVHeavyTasksManager**: File downloads, video processing, ML inference, long-running operations with progress updates\n\n## 💡 Simple Examples\n\n### 1. MemoryCache\nBasic caching operations with TTL, priority-based and LRU eviction.\n\n**Simple Example (Default Configuration):**\n```swift\nimport Monstra\n\n// Create a basic cache with default configuration\nlet cache = MemoryCache\u003cString, Int\u003e()\n\n// Set values with different priorities and TTL\ncache.set(element: 42, for: \"answer\", priority: 10.0, expiredIn: 3600.0) // 1 hour, high priority\ncache.set(element: 100, for: \"score\", priority: 1.0) // Default TTL, low priority\ncache.set(element: nil, for: \"user-999\") // Cache null value\n\n// Get values using the FetchResult enum\nswitch cache.getElement(for: \"answer\") {\ncase .hitNonNullElement(let value):\n    print(\"Found answer: \\(value)\")\ncase .hitNullElement:\n    print(\"Found null value\")\ncase .miss:\n    print(\"Key not found or expired\")\ncase .invalidKey:\n    print(\"Invalid key\")\n}\n\n// Check cache status\nprint(\"Cache count: \\(cache.count)\")\nprint(\"Cache capacity: \\(cache.capacity)\")\nprint(\"Is empty: \\(cache.isEmpty)\")\nprint(\"Is full: \\(cache.isFull)\")\n\n// Remove specific element\nlet removed = cache.removeElement(for: \"score\")\nprint(\"Removed: \\(removed ?? -1)\")\n\n// Clean up expired elements\ncache.removeExpiredElements()\n```\n\n**Detailed Configuration Example:**\n```swift\n// Advanced configuration with all options\nlet imageCache = MemoryCache\u003cString, Data\u003e(\n    configuration: .init(\n        // Thread Safety: Enable DispatchSemaphore synchronization for concurrent access\n        enableThreadSynchronization: true,\n        \n        // Memory \u0026 Capacity Limits: Maximum 100 items, 50MB memory usage\n        memoryUsageLimitation: .init(\n            capacity: 100,    // Maximum number of cached items\n            memory: 50        // Maximum memory usage in MB\n        ),\n        \n        // TTL Settings: How long items stay in cache\n        defaultTTL: 1800.0,              // 30 minutes for regular elements\n        defaultTTLForNullElement: 300.0, // 5 minutes for null/nil elements\n        \n        // Cache Stampede Prevention: Randomize TTL by ±30 seconds\n        ttlRandomizationRange: 30.0,     // Prevents all items expiring simultaneously\n        \n        // Key Validation: Only accept keys starting with \"img_\"\n        keyValidator: { key in\n            return key.hasPrefix(\"img_\")  // Custom validation logic\n        },\n        \n        // Memory Cost Calculation: Use actual data size for eviction decisions\n        costProvider: { data in\n            return data.count             // Return size in bytes\n        }\n    )\n)\n```\n\n### 2. MonoTask  \n**Single Task Execution \u0026 Merging**: Handles individual task execution, request merging and result cache, such as module initialization, configuration file reading, and API call consolidation with result caching (e.g., UserProfile, e-commerce Cart operations)\n\n**Simple Example (Default Configuration):**\n```swift\nimport Monstra\n\n// Create a basic task with minimal configuration\nlet networkTask = MonoTask\u003cData\u003e { callback in\n    // Your network request logic here\n    let url = URL(string: \"https://api.example.com/data\")!\n    URLSession.shared.dataTask(with: url) { data, response, error in\n        if let error = error {\n            callback(.failure(error))\n        } else if let data = data {\n            callback(.success(data))\n        }\n    }.resume()\n}\n\n// Alternatively, you can use an asynchornic block to create MonoTask\n\n// Multiple execution patterns - only one network request\n// Note: All executions benefit from MonoTask's execution merging\n\n// Execute with async/await\nlet result1: Result\u003cData, Error\u003e = await networkTask.asyncExecute()\nswitch result1 {\ncase .success(let data):\n    print(\"Got data: \\(data.count) bytes\")\ncase .failure(let error):\n    print(\"Error: \\(error)\")\n}\n\n// Execute with async/await and try/catch\ndo {\n    let result2: Data = try await networkTask.executeThrows() // Second execution, returns cached result\n    print(\"Result2: \\(result2)\")\n} catch {\n    print(\"Result2 error: \\(error)\")\n}\n\n // Fire-and-forget execution\nnetworkTask.justExecute()\n\n// Callback-based execution\nnetworkTask.execute { result in\n    switch result {\n    case .success(let data):\n        print(\"Result3 (callback): \\(data.count) bytes\")\n    case .failure(let error):\n        print(\"Result3 (callback) error: \\(error)\")\n    }\n}\n```\n\n**Detailed Configuration Example:**\n```swift\n// Advanced configuration with custom retry and queue settings\nlet fileProcessor1 = MonoTask\u003cProcessedData\u003e(\n    retry: 3,  // Simple retry count configuration\n    \n    // Result Caching: Use default cache configuration\n    resultExpireDuration: 300.0,      // 5 minutes cache duration\n    \n    // Task Queue: Custom dispatch queue for task execution\n    taskQueue: DispatchQueue.global(qos: .utility),  // Background priority queue\n    \n    // Callback Queue: Custom dispatch queue for callbacks\n    callbackQueue: DispatchQueue.global(qos: .userInitiated)  // High priority queue\n) { callback in\n    // Your file processing logic here\n    let filePath = \"/path/to/large/file.txt\"\n    do {\n        let data = try Data(contentsOf: URL(fileURLWithPath: filePath))\n        let processedData = ProcessedData(content: data, metadata: [\"size\": data.count])\n        callback(.success(processedData))\n    } catch {\n        callback(.failure(error))\n    }\n}\n// Advanced configuration with custom retry and queue settings\nlet fileProcessor2 = MonoTask\u003cProcessedData\u003e(\n    // Retry Strategy: Exponential backoff with 3 attempts\n    retry: .count(\n        count: 3,    // Maximum retry attempts\n        intervalProxy: .exponentialBackoff(\n            initialTimeInterval: 1.0,  // Start with 1 second delay\n            scaleRate: 2.0             // Double the delay each retry\n        )\n    ),\n    \n    // Result Caching: Use default cache configuration\n    resultExpireDuration: 300.0,      // 5 minutes cache duration\n    \n    // Task Queue: Custom dispatch queue for task execution\n    taskQueue: DispatchQueue.global(qos: .utility),  // Background priority queue\n    \n    // Callback Queue: Custom dispatch queue for callbacks\n    callbackQueue: DispatchQueue.global(qos: .userInitiated)  // High priority queue\n) { callback in\n    // Your file processing logic here\n    let filePath = \"/path/to/large/file.txt\"\n    do {\n        let data = try Data(contentsOf: URL(fileURLWithPath: filePath))\n        let processedData = ProcessedData(content: data, metadata: [\"size\": data.count])\n        callback(.success(processedData))\n    } catch {\n        callback(.failure(error))\n    }\n}\n```\n\n**Async Task Block Example:**\n```swift\n// Async/await initialization with modern Swift concurrency\nlet unzipTask = MonoTask\u003c[String]\u003e(\n    // Retry Strategy: Fixed interval retry for file operations\n    retry: .count(\n        count: 2,    // Retry twice for file system issues\n        intervalProxy: .fixed(timeInterval: 1.0)  // Wait 1 second between retries\n    ),\n    \n    // Result Caching: Cache unzipped file list for 10 minutes\n    resultExpireDuration: 600.0,      // 10 minutes cache duration\n    \n    // Task Queue: Background queue for file operations\n    taskQueue: DispatchQueue.global(qos: .utility),\n    \n    // Callback Queue: Main queue for UI updates\n    callbackQueue: DispatchQueue.main\n) {\n    // Async task block that returns Result directly\n    do {\n        let archivePath = \"/path/to/archive.zip\"\n        let extractPath = \"/path/to/extract/\"\n        \n        // Simulate async unzip operation\n        let extractedFiles = try await unzipArchive(at: archivePath, to: extractPath)\n        return .success(extractedFiles)\n    } catch {\n        return .failure(error)\n    }\n}\n\n// Usage with async/await\nlet extractedFiles = try await unzipTask.executeThrows()\nprint(\"Extracted \\(extractedFiles.count) files\")\n```\n\n### 3. KVLightTasksManager\n**High-Volume Task Execution**: Handles high-volume operations with peak shaving, such as image downloads, local database batch reads, map tile downloads and cache warming operations\n\n**Simple Example (Default Configuration):**\n```swift\nimport Monstra\n\n// Create a lightweight tasks manager for handling image downloads\nlet imageTaskManager = KVLightTasksManager\u003cUIImage\u003e { (imageURL: URL, completion: @escaping (Result\u003cUIImage?, Error\u003e) -\u003e Void) in\n    // Simple image download task\n    URLSession.shared.dataTask(with: imageURL) { data, response, error in\n        if let error = error {\n            completion(.failure(error))\n        } else if let data = data, let image = UIImage(data: data) {\n            completion(.success(image))\n        } else {\n            completion(.failure(NSError(domain: \"ImageError\", code: -1, userInfo: nil)))\n        }\n    }.resume()\n}\n\n// Fetch multiple images\nlet imageURLs = [\n    \"https://example.com/image1.jpg\",\n    \"https://example.com/image2.jpg\", \n    \"https://example.com/image3.jpg\"\n].compactMap { URL(string: $0) }\n\n// Fetch images individually\nfor (index, url) in imageURLs.enumerated() {\n    imageTaskManager.fetch(key: url) { key, result in\n        switch result {\n        case .success(let image):\n            if let image = image {\n                print(\"Image \\(index + 1) downloaded successfully: \\(image.size)\")\n            } else {\n                print(\"Image \\(index + 1) returned nil\")\n            }\n        case .failure(let error):\n            print(\"Image \\(index + 1) failed: \\(error)\")\n        }\n    }\n}\n\n// Fetch multiple images at once with batch callback\nimageTaskManager.fetch(keys: imageURLs) { key, result in\n    switch result {\n    case .success(let image):\n        if let image = image {\n            print(\"Image downloaded: \\(image.size)\")\n        } else {\n            print(\"Image returned nil\")\n        }\n    case .failure(let error):\n        print(\"Image failed: \\(error)\")\n    }\n}\n```\n\n**Batch Processing Example:**\n```swift\n// Create a manager for batch fetching user profile data\nlet userProfileManager = KVLightTasksManager\u003c[String: UserProfile?]\u003e { (userIDs: [String], completion: @escaping (Result\u003c[String: UserProfile?], Error\u003e) -\u003e Void) in\n    // Simulate batch API call to fetch multiple user profiles\n    DispatchQueue.global(qos: .utility).async {\n        // Simulate network delay\n        Thread.sleep(forTimeInterval: 0.1)\n        \n        var profiles: [String: UserProfile?] = [:]\n        \n        // Simulate batch API response\n        for userID in userIDs {\n            let profile = UserProfile(\n                id: userID,\n                name: \"User \\(userID)\",\n                email: \"user\\(userID)@example.com\",\n                avatar: \"https://example.com/avatars/\\(userID).jpg\"\n            )\n            profiles[userID] = profile\n        }\n        \n        completion(.success(profiles))\n    }\n}\n\n// Fetch multiple user profiles in a single batch\nlet userIDs = [\"user1\", \"user2\", \"user3\"]\n\n// Using batch callback for all results at once\nuserProfileManager.fetch(keys: userIDs, multiCallback: { results in\n    print(\"Batch loaded \\(results.count) users:\")\n    for (userID, result) in results {\n        switch result {\n        case .success(let profile):\n            if let profile = profile {\n                print(\"  ✓ \\(profile.name) (\\(profile.email))\")\n            } else {\n                print(\"  - \\(userID): No profile found\")\n            }\n        case .failure(let error):\n            print(\"  ✗ \\(userID): \\(error)\")\n        }\n    }\n})\n\n// Using individual callbacks for each user (still benefits from batch processing)\nuserProfileManager.fetch(keys: userIDs) { userID, result in\n    switch result {\n    case .success(let profile):\n        if let profile = profile {\n            print(\"Individual: \\(profile.name) loaded\")\n        } else {\n            print(\"Individual: \\(userID) - No profile found\")\n        }\n    case .failure(let error):\n        print(\"Individual: \\(userID) - \\(error)\")\n    }\n}\n```\n\n**Advanced Configuration Example:**\n```swift\n// Create a manager with custom configuration for image downloads\nlet imageManager = KVLightTasksManager\u003cUIImage\u003e(\n    config: .init(\n        dataProvider: .multiprovide(maximumBatchCount: 4) { (imageURLs: [String], completion: @escaping (Result\u003c[String: UIImage?], Error\u003e) -\u003e Void) in\n            // Download multiple images in parallel\n            let group = DispatchGroup()\n            var results = [String: UIImage?]()\n            let lock = NSLock()\n            \n            for urlString in imageURLs {\n                group.enter()\n                \n                guard let url = URL(string: urlString) else {\n                    lock.lock()\n                    results[urlString] = nil\n                    lock.unlock()\n                    group.leave()\n                    continue\n                }\n                \n                URLSession.shared.dataTask(with: url) { data, response, error in\n                    defer { group.leave() }\n                    \n                    lock.lock()\n                    if let data = data, let image = UIImage(data: data) {\n                        results[urlString] = image\n                    } else {\n                        results[urlString] = nil\n                    }\n                    lock.unlock()\n                }.resume()\n            }\n            \n            group.notify(queue: .main) {\n                completion(.success(results))\n            }\n        },\n        maxNumberOfQueueingTasks: 32,     // Queue up to 32 image requests\n        maxNumberOfRunningTasks: 4,       // Download 4 images simultaneously\n        retryCount: 1,                    // Retry failed downloads once\n        PriorityStrategy: .FIFO,          // Process oldest requests first\n        cacheConfig: .init(\n            capacity: 100,                // Cache up to 100 images\n            memory: 50,                   // 50MB memory limit\n            defaultTTL: 3600.0,           // 1 hour cache duration\n            enableThreadSynchronization: true\n        )\n    )\n)\n\n// Download multiple images\nlet imageURLs = [\n    \"https://example.com/image1.jpg\",\n    \"https://example.com/image2.jpg\",\n    \"https://example.com/image3.jpg\"\n]\n\n// Download all images\nimageManager.fetch(keys: imageURLs) { url, result in\n    switch result {\n    case .success(let image):\n        if let image = image {\n            print(\"✓ Downloaded: \\(image.size)\")\n        } else {\n            print(\"- Failed to download: \\(url)\")\n        }\n    case .failure(let error):\n        print(\"✗ Error: \\(error)\")\n        }\n    }\n```\n\n### 4. KVHeavyTasksManager\n\n**Resource-Intensive Operations**: Handles demanding tasks such as large file downloads, video processing, and ML inference with comprehensive progress tracking\n\n#### SimpleDataProvider implementation\n\nNotes:\n- `SimpleDataProvider` is intentionally minimal (blocking I/O, no progress/resume) for clarity.\n- For production downloads with progress/resume/cancellation, see the advanced providers in\n  `Examples/KVHeavyTasksManager/LargeFileDownloadManagement`.\n\n```swift\nimport Foundation\nimport Monstra\n\nenum SimpleDataProviderEvent {\n    case didStart\n    case didFinish\n}\n\n/// Minimal synchronous provider for educational purposes only.\nclass SimpleDataProvider: Monstra.KVHeavyTaskBaseDataProvider\u003cURL, Data, SimpleDataProviderEvent\u003e, Monstra.KVHeavyTaskDataProviderInterface {\n    let semaphore = DispatchSemaphore(value: 1)\n    var isRunning = false {\n        didSet { customEventPublisher(isRunning ? .didStart : .didFinish) }\n    }\n\n    func start() {\n        semaphore.wait(); defer { semaphore.signal() }\n        guard !isRunning else { return }\n        isRunning = true\n\n        DispatchQueue.global().async {\n            let result: Result\u003cData?, Error\u003e\n            do {\n                let data = try Data(contentsOf: self.key, options: .mappedIfSafe)\n                result = .success(data)\n            } catch {\n                result = .failure(error)\n            }\n\n            self.semaphore.wait(); defer { self.semaphore.signal() }\n            guard self.isRunning else { return }\n            self.isRunning = false\n            self.resultPublisher(result)\n        }\n    }\n\n    @discardableResult\n    func stop() -\u003e KVHeavyTaskDataProviderStopAction {\n        semaphore.wait(); defer { semaphore.signal() }\n        guard isRunning else { return .dealloc }\n        isRunning = false\n        return .dealloc\n    }\n}\n```\n\n#### Minimal usage\n\n```swift\nimport Monstra\n\n// Educational provider that does a blocking read on a background queue\n// See: Examples/KVHeavyTasksManager/LargeFileDownloadManagement/Sources/.../SimpleDataProvider.swift\ntypealias SimpleHeavyManager = KVHeavyTasksManager\u003cURL, Data, SimpleDataProviderEvent, SimpleDataProvider\u003e\n\nlet manager = SimpleHeavyManager(config: .init())\nlet fileURL = URL(string: \"https://example.com/file.bin\")!\n\n// Observe simple start/finish events and get the result\nmanager.fetch(\n    key: fileURL,\n    customEventObserver: { event in\n        switch event {\n        case .didStart:  print(\"SimpleDataProvider: didStart\")\n        case .didFinish: print(\"SimpleDataProvider: didFinish\")\n        }\n    },\n    result: { result in\n        switch result {\n        case .success(let data):\n            print(\"Downloaded: \\(data.count) bytes\")\n        case .failure(let error):\n            print(\"Failed: \\(error)\")\n        }\n    }\n)\n```\n\n## 🚀 Advanced Examples\n\n### **⚡ MonoTask - Task Execution Scenarios**\n\u003ctable width=\"100%\"\u003e\n  \u003ccolgroup\u003e\n    \u003ccol width=\"40%\" /\u003e\n    \u003ccol width=\"40%\" /\u003e\n    \u003ccol width=\"20%\" /\u003e\n  \u003c/colgroup\u003e\n  \u003cthead\u003e\n    \u003ctr\u003e\n      \u003cth\u003eScenarios\u003c/th\u003e\n      \u003cth\u003eBest Practices\u003c/th\u003e\n      \u003cth\u003eExample Link\u003c/th\u003e\n    \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eModule Initialization\u003c/td\u003e\n      \u003ctd\u003eCache app configuration with retry logic\u003c/td\u003e\n      \u003ctd\u003e\u003ca href=\"Examples/MonoTask/ModuleInitialization\"\u003eModule Initialization\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eUserProfile Manager\u003c/td\u003e\n      \u003ctd\u003eSingle-instance user profile management with caching\u003c/td\u003e\n      \u003ctd\u003e\u003ca href=\"Examples/MonoTask/UserProfileManager\"\u003eUserProfile Manager\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n \u003c/table\u003e\n\n### **🚀 KVLightTasksManager - Light Task Scenarios**\n\u003ctable width=\"100%\"\u003e\n  \u003ccolgroup\u003e\n    \u003ccol width=\"40%\" /\u003e\n    \u003ccol width=\"40%\" /\u003e\n    \u003ccol width=\"20%\" /\u003e\n  \u003c/colgroup\u003e\n  \u003cthead\u003e\n    \u003ctr\u003e\n      \u003cth\u003eScenarios\u003c/th\u003e\n      \u003cth\u003eBest Practices\u003c/th\u003e\n      \u003cth\u003eExample Link\u003c/th\u003e\n    \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eObject Fetch Task\u003c/td\u003e\n      \u003ctd\u003eBatch fetch objects by ID list with performance enhancement\u003c/td\u003e\n      \u003ctd\u003e\u003ca href=\"Examples/KVLightTasksManager/ObjectFetchTask\"\u003eObject Fetch Task\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n \u003c/table\u003e\n\n### **🏗️ KVHeavyTasksManager - Heavy Task Scenarios**\n\u003ctable width=\"100%\"\u003e\n  \u003ccolgroup\u003e\n    \u003ccol width=\"40%\" /\u003e\n    \u003ccol width=\"40%\" /\u003e\n    \u003ccol width=\"20%\" /\u003e\n  \u003c/colgroup\u003e\n  \u003cthead\u003e\n    \u003ctr\u003e\n      \u003cth\u003eScenarios\u003c/th\u003e\n      \u003cth\u003eBest Practices\u003c/th\u003e\n      \u003cth\u003eExample Link\u003c/th\u003e\n    \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eLarge File Download Management\u003c/td\u003e\n      \u003ctd\u003eLarge file downloads with progress tracking\u003c/td\u003e\n      \u003ctd\u003e\u003ca href=\"Examples/KVHeavyTasksManager/LargeFileDownloadManagement\"\u003eLarge File Downloader\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eLarge File Unzip\u003c/td\u003e\n      \u003ctd\u003eProcessing large archive files with progress tracking and resource management\u003c/td\u003e\n      \u003ctd\u003e\u003ca href=\"Examples/KVHeavyTasksManager/LargeFileUnzip\"\u003eLarge File Unzip\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n \u003c/table\u003e\n\n## 📋 Requirements\n\n### Platform Support\n- **iOS**: 13.0+\n- **macOS**: 10.15+\n- **tvOS**: 13.0+\n- **watchOS**: 6.0+\n\n### Swift Version\n- **Swift**: 5.5+\n\n### Dependencies\n- **Foundation**: Built-in (no external dependencies)\n- **Alamofire**: Only for example executable (not required for core library)\n\n## 🛡️ Key Advantages \u0026 Protection Mechanisms\n\n### **Monstore Protection Features**\n\n### **Cache Stampede Prevention**\nMonstra prevents cache stampede attacks through TTL randomization. When multiple cache entries expire simultaneously, it can cause a sudden surge of requests to your backend. Monstra randomizes expiration times within a configurable range to distribute the load.\n\n```swift\nlet cache = MemoryCache\u003cString, Data\u003e(\n    configuration: .init(\n        ttlRandomizationRange: 30.0 // ±30 seconds randomization\n    )\n)\n```\n\n### **Avalanche Protection**\nMonstra protects against memory avalanches by implementing intelligent eviction policies. When memory usage approaches limits, the system automatically evicts the least valuable entries based on priority, recency, and expiration status.\n\n```swift\nlet cache = MemoryCache\u003cString, UIImage\u003e(\n    configuration: .init(\n        memoryUsageLimitation: .init(\n            capacity: 1000,    // Max 1000 images\n            memory: 500        // Max 500MB\n        )\n    )\n)\n```\n\n### **Breakdown Protection**\nMonstra prevents cache breakdowns through priority-based LRU eviction. Critical data with higher priority is retained longer, while less important data is evicted first when capacity is reached.\n\n```swift\n// Set high priority for critical data\ncache.set(element: userProfile, for: \"user-123\", priority: 10.0)\n\n// Set low priority for temporary data\ncache.set(element: searchResults, for: \"search-query\", priority: 1.0)\n```\n\n### **Null Element Caching**\nMonstra supports caching null/nil elements with separate TTL configuration, preventing repeated database queries for non-existent data.\n\n```swift\nlet cache = MemoryCache\u003cString, User?\u003e(\n    configuration: .init(\n        defaultTTL: 3600.0,           // Regular data: 1 hour\n        defaultTTLForNullElement: 300.0  // Null data: 5 minutes\n    )\n)\n\n// Cache both existing and non-existing users\ncache.set(element: user, for: \"user-123\")      // Regular cache\ncache.set(element: nil, for: \"user-999\")      // Null cache\n```\n\n### **Monstask Protection Features**\n\n#### **MonoTask - Execution Merging \u0026 Deduplication**\nMonoTask prevents duplicate work through intelligent execution merging. When multiple concurrent requests are made for the same task, only one execution occurs while all callbacks receive the same result.\n\n```swift\nlet task = MonoTask\u003cString\u003e(resultExpireDuration: 60.0) { callback in\n    // Expensive network call\n    performExpensiveOperation(callback)\n}\n\n// Multiple concurrent calls - only one network request\nTask {\n    let result1 = await task.asyncExecute() // Network call happens\n    let result2 = await task.asyncExecute() // Returns cached result\n    let result3 = await task.asyncExecute() // Returns cached result\n}\n```\n\n#### **MonoTask - Advanced Retry Strategies**\nMonoTask provides sophisticated retry mechanisms with exponential backoff, fixed intervals, and hybrid approaches to handle transient failures gracefully.\n\n```swift\n// Exponential backoff with 3 retries\nlet retryTask = MonoTask\u003cData\u003e(\n    retry: .count(\n        count: 3, \n        intervalProxy: .exponentialBackoff(\n            initialTimeInterval: 1.0, \n            scaleRate: 2.0\n        )\n    ),\n    resultExpireDuration: 300.0\n) { callback in\n    performNetworkRequest(callback)\n}\n\n// Fixed interval retry\nlet fixedRetryTask = MonoTask\u003cData\u003e(\n    retry: .count(\n        count: 5, \n        intervalProxy: .fixed(timeInterval: 2.0)\n    )\n) { callback in\n    performDatabaseQuery(callback)\n}\n```\n\n#### **MonoTask - Execution State Management**\nMonoTask provides fine-grained control over task execution states with cancellation, restart, and completion strategies.\n\n```swift\n// Cancel ongoing execution immediately\ntask.clearResult(ongoingExecutionStrategy: .cancel)\n\n// Let execution complete, then restart\ntask.clearResult(ongoingExecutionStrategy: .restart)\n\n// Let execution complete normally, just clear cache\ntask.clearResult(ongoingExecutionStrategy: .allowCompletion)\n```\n\n#### **MonoTask - Multiple Execution Patterns**\nMonoTask supports various execution patterns to fit different use cases and coding styles.\n\n```swift\n// Async/await (recommended for modern Swift)\nlet result = await task.asyncExecute()\nswitch result {\ncase .success(let data):\n    updateUI(with: data)\ncase .failure(let error):\n    showErrorMessage(error)\n}\n\n// Callback-based (for legacy code integration)\ntask.execute { result in\n    switch result {\n    case .success(let data):\n        updateUI(with: data)\n    case .failure(let error):\n        showErrorMessage(error)\n    }\n}\n\n// Fire-and-forget (for pre-warming cache)\ntask.justExecute()\n// Later, this will likely return cached result\nlet result = await task.asyncExecute()\n```\n\n#### **Task Managers - Priority-Based Scheduling**\nKVLightTasksManager and KVHeavyTasksManager provide priority-based scheduling with LIFO/FIFO strategies for optimal resource utilization.\n\n```swift\nlet lightManager = KVLightTasksManager\u003cString, User\u003e(\n    config: .init(\n        dataProvider: .asyncMonoprovide { key in\n            try await API.fetchUser(id: key)\n        },\n        PriorityStrategy: .LIFO,  // Latest requests get priority\n        maxNumberOfRunningTasks: 4,\n        maxNumberOfQueueingTasks: 256\n    )\n)\n\nlet heavyManager = KVHeavyTasksManager\u003cString, Video\u003e(\n    config: .init(\n        dataProvider: .asyncMonoprovide { key in\n            try await VideoProcessor.process(key)\n        },\n        PriorityStrategy: .FIFO,  // Fair processing order\n        maxNumberOfRunningTasks: 2,  // Limited for heavy operations\n        maxNumberOfQueueingTasks: 64\n    )\n)\n```\n\n## 🤝 Contributing\n\nWe welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.\n\n### Development Workflow\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Make your changes\n4. Add tests for new functionality\n5. Ensure all tests pass (`swift test`)\n6. Run linting (`swiftlint lint Sources/`)\n7. Commit your changes (`git commit -m 'Add amazing feature'`)\n8. Push to the branch (`git push origin feature/amazing-feature`)\n9. Submit a pull request\n\n### Code Style\n- Follow Swift API Design Guidelines\n- Use meaningful variable and function names\n- Add comprehensive documentation comments\n- Ensure all public APIs have unit tests\n- Maintain performance benchmarks\n\n## 📄 License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## 🙏 Acknowledgments\n\n- Inspired by high-performance cache implementations\n- Built with Swift's excellent type system and performance characteristics\n- Tested extensively for production readiness\n- Special thanks to the Swift community for feedback and contributions\n- Special thanks to [Cursor](https://cursor.sh) - AI-first code editor for enhancing development productivity\n\n---\n\n**Made with ❤️ for the Swift community** \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyangchenlarkin%2FMonstra","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyangchenlarkin%2FMonstra","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyangchenlarkin%2FMonstra/lists"}