Popular Searches
Popular Course Categories
Popular Courses

Implementing Background Tasks Using BackgroundTasks Framework

Implementing Background Tasks Using BackgroundTasks Framework

Background Tasks, Push Notifications, and App Services

Implementing Background Tasks Using BackgroundTasks Framework

Course: iOS App Development

Topic: Implementing Background Tasks Using BackgroundTasks Framework

Course Link: iOS App Development Training

Demo Link: Register for a Free Course Demo

Website: JustAcademy


1. Introduction to Background Tasks in iOS

Background tasks allow an iOS application to perform selected operations when the application is not actively visible on the screen. These operations may include refreshing application content, synchronizing information with a server, cleaning temporary files, processing stored data, and maintaining a local database.

iOS manages background execution carefully to protect battery life, memory, and system performance. Unlike desktop applications, an iOS app cannot continue executing arbitrary code indefinitely after the user switches to another application. The operating system decides when background work can run and how much execution time it receives.

Apple provides the BackgroundTasks framework to schedule and execute suitable background operations. Developers register task handlers, submit task requests, and implement code that can safely finish or pause when the system requires it.

Why Are Background Tasks Important?

  • Keep application content reasonably up to date.
  • Synchronize local information with remote servers.
  • Perform database maintenance and cleanup operations.
  • Process data when the device has suitable resources.
  • Improve the experience when users reopen the application.
  • Reduce unnecessary foreground loading and waiting time.

Examples of Background Operations

Application Background Operation
News Application Refresh latest news articles.
Shopping Application Synchronize product and order information.
Messaging Application Refresh selected conversation data.
Fitness Application Process and synchronize activity summaries.
Document Application Perform file synchronization and maintenance.
Productivity Application Clean temporary files and update cached information.

2. Understanding the BackgroundTasks Framework

The BackgroundTasks framework provides APIs that allow applications to request background execution. The operating system evaluates these requests according to device conditions, application usage patterns, battery level, and available resources.

The framework does not guarantee that a task will start at an exact time. Instead, it allows an application to communicate the type of work it needs to perform and the earliest time that work should become eligible.

Important BackgroundTasks Classes

Class Purpose
BGTaskScheduler Registers task handlers and submits background task requests.
BGTask Base class representing a background task managed by the system.
BGAppRefreshTask Represents a short task used to refresh application content.
BGProcessingTask Represents a longer processing or maintenance task.
BGAppRefreshTaskRequest Creates a request for an application refresh task.
BGProcessingTaskRequest Creates a request for a processing task.
BGContinuedProcessingTask Supports certain user-initiated work that starts in the foreground and can continue after the app enters the background on supported systems.

3. Types of Background Tasks in iOS

The most commonly used scheduled task types are BGAppRefreshTask and BGProcessingTask. They are designed for different workloads and should not be treated as interchangeable.

3.1 BGAppRefreshTask

BGAppRefreshTask is intended for short operations that update application content. It is useful when an application needs to retrieve a small amount of information before the user opens it again.

Examples:

  • Fetching the latest news headlines.
  • Updating a weather summary.
  • Refreshing a user's account information.
  • Retrieving recent notifications or messages from a server.

App refresh tasks are relatively short. The system chooses when to execute them, and developers should keep the work efficient.

3.2 BGProcessingTask

BGProcessingTask is intended for operations that require more processing time than a typical content refresh. It is suitable for maintenance and processing jobs that can wait until the system has appropriate resources.

Examples:

  • Cleaning old database records.
  • Processing locally stored information.
  • Performing data synchronization.
  • Generating thumbnails for stored files.
  • Performing application maintenance.

Processing tasks may be configured to require network connectivity or external power. The system can still interrupt a task, so the operation must support cancellation and recovery.

3.3 BGContinuedProcessingTask

On supported newer iOS versions, BGContinuedProcessingTask supports certain long-running operations that begin because of a user action while the app is in the foreground. If the user backgrounds the app before the operation finishes, the system can allow the work to continue under the applicable conditions.

Examples include exporting a video, processing a large collection of images, or performing a user-requested operation that needs additional time. This API is different from ordinary scheduled refresh and processing tasks because the work starts in response to a foreground action.

Comparison of Background Task Types

Feature BGAppRefreshTask BGProcessingTask BGContinuedProcessingTask
Main Purpose Refresh content Longer maintenance and processing Continue user-initiated work
Typical Start Scheduled by the system Scheduled by the system Started from foreground work
Execution Short duration Can run for longer periods Can continue after the app is backgrounded
Common Example Fetch latest articles Clean database records Continue a video export
Scheduling Control System decides the execution time System decides based on conditions Uses a user-initiated task request and supported system rules

4. Importing the BackgroundTasks Framework

To use background task APIs, import the BackgroundTasks framework into the relevant Swift file.

import UIKit
import BackgroundTasks

class AppDelegate: UIResponder, UIApplicationDelegate {
    // Background task configuration
}

The framework provides the scheduler, task request classes, and task objects required to register and execute background operations.

5. Configuring Background Modes in Xcode

Before scheduling background tasks, configure the capabilities required by the application.

Configuration Steps

  1. Open the iOS project in Xcode.
  2. Select the application target from the Project Navigator.
  3. Open the Signing & Capabilities tab.
  4. Click + Capability if Background Modes is not already available.
  5. Add the Background Modes capability.
  6. Enable Background fetch for app refresh tasks.
  7. Enable Background processing for processing tasks.
  8. Save the project configuration.

Background Modes Configuration Table

Background Mode Purpose
Background fetch Allows the application to request background content refresh opportunities.
Background processing Allows the application to request background processing opportunities.

Enable only the background modes that match the application's actual requirements. Adding a capability does not guarantee that iOS will execute a task at a particular time.

6. Configuring Permitted Background Task Identifiers

Every scheduled task must use a unique identifier. The identifier must be declared in the application's permitted background task scheduler identifiers list.

For example, an application may define separate identifiers for refreshing content and cleaning a database.

Info.plist Configuration

Add the BGTaskSchedulerPermittedIdentifiers key to the application's Info.plist file. Its value must be an array containing the identifiers used by the application.

<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
    <string>com.justacademy.iosapp.refresh</string>
    <string>com.justacademy.iosapp.database-cleanup</string>
</array>

Understanding Task Identifiers

  • Use a unique identifier for every registered task.
  • Prefer reverse-domain naming conventions.
  • Keep identifiers consistent between Info.plist and Swift code.
  • Do not use an identifier that has not been declared as permitted.
  • Avoid changing identifiers without updating the application configuration.

7. Registering a Background Task

Registration connects a task identifier with the code that should execute when the system launches the task. Register all required handlers early in the application launch sequence.

Example: Registering an App Refresh Task

import UIKit
import BackgroundTasks

class AppDelegate: UIResponder, UIApplicationDelegate {

    let refreshIdentifier = "com.justacademy.iosapp.refresh"

    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions:
        [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {

        BGTaskScheduler.shared.register(
            forTaskWithIdentifier: refreshIdentifier,
            using: nil
        ) { task in

            guard let refreshTask = task as? BGAppRefreshTask else {
                task.setTaskCompleted(success: false)
                return
            }

            self.handleAppRefresh(task: refreshTask)
        }

        return true
    }

    func handleAppRefresh(task: BGAppRefreshTask) {
        print("App refresh task started")
        task.setTaskCompleted(success: true)
    }
}

Explanation

  • BGTaskScheduler.shared: Accesses the shared task scheduler.
  • register(forTaskWithIdentifier:using:launchHandler:): Registers the identifier and its launch handler.
  • refreshIdentifier: Stores the unique task identifier.
  • BGAppRefreshTask: Represents the app refresh task received by the handler.
  • handleAppRefresh(task:): Contains the work that should be performed.

8. Scheduling an App Refresh Task

After registering the handler, the application can submit a request to schedule a future refresh opportunity. The BGAppRefreshTaskRequest class represents this request.

Example: Scheduling a Refresh

func scheduleAppRefresh() {

    let request = BGAppRefreshTaskRequest(
        identifier: "com.justacademy.iosapp.refresh"
    )

    request.earliestBeginDate =
        Date(timeIntervalSinceNow: 15 * 60)

    do {
        try BGTaskScheduler.shared.submit(request)
        print("App refresh request submitted")
    } catch {
        print("Unable to schedule refresh: \(error)")
    }
}

Explanation

  • Create a BGAppRefreshTaskRequest using the registered identifier.
  • Set earliestBeginDate to indicate the earliest time the task may run.
  • Submit the request through BGTaskScheduler.shared.submit().
  • Handle errors because the system may reject an invalid or unavailable request.

Important: earliestBeginDate is not an exact execution time. It indicates when the request becomes eligible to run. iOS decides the actual execution time.

9. Performing Data Refresh Operations

A refresh task commonly retrieves information from a server and updates local application storage. The operation should be asynchronous, efficient, and designed to handle network failures.

Example: Fetching Data Using URLSession

import Foundation

struct Article: Decodable {
    let id: Int
    let title: String
}

func fetchLatestArticles() async throws -> [Article] {

    guard let url = URL(
        string: "https://example.com/api/articles"
    ) else {
        throw URLError(.badURL)
    }

    let (data, response) = try await URLSession.shared.data(
        from: url
    )

    guard let httpResponse = response as? HTTPURLResponse,
          (200...299).contains(httpResponse.statusCode) else {
        throw URLError(.badServerResponse)
    }

    return try JSONDecoder().decode([Article].self, from: data)
}

Explanation

  • URLSession sends a network request to the configured API endpoint.
  • The async function waits for the network response without blocking the main thread.
  • The HTTP status code is checked before processing the response.
  • JSONDecoder converts the response data into Article objects.
  • The application can save the returned articles into local storage.

For production applications, use a real API endpoint, appropriate authentication, request timeouts, and robust error handling.

10. Handling Task Expiration

Background execution time is limited. If iOS needs to stop a running task, it invokes the task's expirationHandler. The application should use this handler to cancel ongoing work and release resources safely.

Example: Expiration Handler

func handleAppRefresh(task: BGAppRefreshTask) {

    let operation = BlockOperation {
        print("Refreshing application content...")
    }

    task.expirationHandler = {
        operation.cancel()
        print("Background task expired")
    }

    operation.completionBlock = {
        let succeeded = !operation.isCancelled
        task.setTaskCompleted(success: succeeded)
    }

    OperationQueue().addOperation(operation)
}

Why Is the Expiration Handler Important?

  • It helps the application respond when execution time runs out.
  • It allows ongoing operations to be cancelled.
  • It prevents unnecessary work from continuing after expiration.
  • It helps the application release resources and preserve data safely.
  • It supports more reliable background task completion.

For complex operations, use a retained operation queue or task manager rather than creating temporary objects that may disappear while work is running.

11. Completing a Background Task

When the requested work finishes, the application must notify the system using setTaskCompleted(success:). This communicates whether the task completed successfully.

func finishBackgroundTask(
    task: BGTask,
    success: Bool
) {
    task.setTaskCompleted(success: success)
}

Completion Guidelines

  • Call setTaskCompleted(success:) when the operation has finished.
  • Report success only when the intended work has completed successfully.
  • Report failure when the operation fails or is cancelled before completion.
  • Make sure every execution path reaches task completion.
  • Do not report completion immediately while asynchronous work is still running.

12. Implementing BGProcessingTask

BGProcessingTask is suitable for longer background operations such as database maintenance, file processing, and data cleanup.

Example: Registering a Processing Task

func registerProcessingTask() {

    BGTaskScheduler.shared.register(
        forTaskWithIdentifier:
            "com.justacademy.iosapp.database-cleanup",
        using: nil
    ) { task in

        guard let processingTask = task as? BGProcessingTask else {
            task.setTaskCompleted(success: false)
            return
        }

        self.handleDatabaseCleanup(task: processingTask)
    }
}

Scheduling a Processing Task

func scheduleDatabaseCleanup() {

    let request = BGProcessingTaskRequest(
        identifier: "com.justacademy.iosapp.database-cleanup"
    )

    request.requiresNetworkConnectivity = false
    request.requiresExternalPower = true

    do {
        try BGTaskScheduler.shared.submit(request)
        print("Database cleanup scheduled")
    } catch {
        print("Scheduling failed: \(error)")
    }
}

Understanding Processing Requirements

Property Purpose
requiresNetworkConnectivity Indicates whether the task needs network connectivity.
requiresExternalPower Indicates whether the task should require external power.
earliestBeginDate Specifies the earliest date and time at which the request becomes eligible.

These properties express requirements to the system. They do not force the device to run the task immediately.

13. Performing Database Maintenance in the Background

Database maintenance is a common use case for BGProcessingTask. An application may need to remove outdated records, rebuild indexes, or organize locally stored information.

Example: Database Cleanup Function

func cleanOldRecords() throws {

    // Example maintenance operation.
    // Replace this section with the application's
    // actual database implementation.

    print("Checking outdated database records")
    print("Removing records that are no longer required")
    print("Database cleanup completed")
}

Handling the Processing Task

func handleDatabaseCleanup(task: BGProcessingTask) {

    let queue = OperationQueue()
    let operation = BlockOperation()

    operation.addExecutionBlock {
        do {
            try self.cleanOldRecords()
        } catch {
            print("Database cleanup error: \(error)")
        }
    }

    task.expirationHandler = {
        operation.cancel()
    }

    operation.completionBlock = {
        task.setTaskCompleted(
            success: !operation.isCancelled
        )
    }

    queue.addOperation(operation)
}

For a real database implementation, check cancellation during long operations and use transactions where appropriate. A cancelled cleanup should leave the database in a consistent state.

14. Rescheduling Background Tasks

Background task requests are not permanent repeating schedules. If an application wants another refresh opportunity, it generally submits a new request after handling the current task.

Example: Rescheduling After Completion

func handleAppRefresh(task: BGAppRefreshTask) {

    scheduleAppRefresh()

    Task {
        var succeeded = false

        do {
            let articles = try await fetchLatestArticles()
            print("Received \(articles.count) articles")
            succeeded = true
        } catch {
            print("Refresh failed: \(error)")
        }

        task.setTaskCompleted(success: succeeded)
    }
}

This example demonstrates the rescheduling pattern. In a production implementation, coordinate cancellation and task expiration with the asynchronous operation so that the task is not marked complete while work is still running.

15. Using Background Tasks with SwiftUI

SwiftUI applications can use BackgroundTasks through an application lifecycle integration. One approach is to use an AppDelegate through UIApplicationDelegateAdaptor and register the task handlers during application launch.

Example: Connecting AppDelegate to SwiftUI

import SwiftUI
import UIKit
import BackgroundTasks

@main
struct BackgroundDemoApp: App {

    @UIApplicationDelegateAdaptor(AppDelegate.self)
    var appDelegate

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

AppDelegate Example

class AppDelegate: NSObject, UIApplicationDelegate {

    let refreshID = "com.justacademy.iosapp.refresh"

    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions:
        [UIApplication.LaunchOptionsKey: Any]? = nil
    ) -> Bool {

        BGTaskScheduler.shared.register(
            forTaskWithIdentifier: refreshID,
            using: nil
        ) { task in

            guard let refreshTask = task as? BGAppRefreshTask else {
                task.setTaskCompleted(success: false)
                return
            }

            self.performRefresh(task: refreshTask)
        }

        return true
    }

    func performRefresh(task: BGAppRefreshTask) {

        task.expirationHandler = {
            print("Refresh task expired")
        }

        Task {
            var success = false

            do {
                let articles = try await fetchLatestArticles()
                print("Articles received: \(articles.count)")
                success = true
            } catch {
                print("Refresh error: \(error)")
            }

            task.setTaskCompleted(success: success)
        }
    }
}

In a production SwiftUI application, the asynchronous operation should also respond to task expiration by cancelling its work. The application should use a consistent task registration and scheduling strategy.

16. Testing Background Tasks in Xcode

Background tasks are controlled by iOS, so they may not execute immediately after submission. Developers can use Xcode debugging tools to simulate task launches and expiration during development.

Testing Steps

  1. Run the application on a supported iOS simulator or physical device.
  2. Confirm that the task identifier is registered and permitted.
  3. Submit the background task request.
  4. Use Xcode's debugging options to simulate a background task launch where supported.
  5. Observe the launch handler and task execution logs.
  6. Test the expiration path and confirm that ongoing work responds to cancellation.
  7. Check whether the task reports successful or unsuccessful completion correctly.

Testing Checklist

  • Task identifier matches the Info.plist entry.
  • Background mode is enabled when required.
  • Task handler is registered early during launch.
  • Task request is submitted without errors.
  • Expiration handling is implemented.
  • Task completion is reported correctly.
  • Application data remains consistent after interruption.

17. Debugging Common Background Task Errors

Problem Possible Cause Solution
Task does not launch System has not selected the request for execution. Test using supported Xcode simulation tools and verify scheduling configuration.
Not permitted error Identifier is missing from BGTaskSchedulerPermittedIdentifiers. Add the exact identifier to Info.plist.
Registration fails Duplicate registration or incorrect identifier. Register each identifier once and verify its spelling.
Task expires Operation takes longer than the available execution time. Reduce the workload and implement cancellation.
Network request fails Network is unavailable or the server returns an error. Handle network errors and retry safely when appropriate.
Data is incomplete Task is interrupted before persistence finishes. Use atomic writes, checkpoints, and database transactions.
Task runs only sometimes Background scheduling is discretionary. Do not depend on an exact execution time.

18. Best Practices for Background Task Implementation

  • Keep tasks focused: Perform only the work necessary for the requested operation.
  • Respect system scheduling: Do not expect a task to run at an exact time.
  • Register early: Register task handlers during the application's launch sequence.
  • Use unique identifiers: Keep identifiers consistent across code and Info.plist.
  • Handle expiration: Cancel or safely stop ongoing operations when the system requests it.
  • Report completion: Call setTaskCompleted(success:) when the task finishes.
  • Save progress: Store checkpoints so interrupted work can resume safely.
  • Reduce battery usage: Avoid unnecessary network calls and intensive processing.
  • Use suitable APIs: Choose URLSession background transfers for large file uploads and downloads rather than treating BGAppRefreshTask as a file-transfer service.
  • Test interruption: Verify that the application remains stable if a task is cancelled.
  • Protect user data: Use secure storage and authenticated network requests.
  • Monitor performance: Track task duration, failures, and resource usage.

19. Difference Between BackgroundTasks and beginBackgroundTask

Developers sometimes confuse scheduled background tasks with the UIKit beginBackgroundTask API. These APIs serve different purposes.

Feature BackgroundTasks Framework beginBackgroundTask
Purpose Requests scheduled background execution. Requests limited extra time to finish current work when entering the background.
Typical Use Content refresh and deferred maintenance. Finishing a save or other critical operation.
Scheduling Managed by BGTaskScheduler. Started directly by the application.
Execution Time Depends on task type and system conditions. Limited system-granted time.
Completion BGTask.setTaskCompleted(success:) UIApplication.endBackgroundTask(_:)

20. Practical Project: Background News Refresh Application

In this practical project, you will build a simple news application that requests background refresh opportunities and updates its locally stored news content.

Project Objectives

  • Create a SwiftUI news application.
  • Register a BGAppRefreshTask.
  • Schedule a refresh request.
  • Fetch news data from a remote API.
  • Save the latest results locally.
  • Handle expiration and network errors.
  • Display updated news when the user opens the application.

Project Workflow

  1. The user opens the news application.
  2. The application registers its background refresh handler during launch.
  3. The application submits a refresh request.
  4. At an appropriate time, iOS may launch the application in the background.
  5. The registered handler starts the news refresh operation.
  6. The application retrieves the latest news from the server.
  7. The received information is saved to local storage.
  8. The application reports task completion to the system.
  9. The application schedules another refresh request if needed.
  10. When the user opens the application, the latest available local content is displayed.

Suggested Project Structure

BackgroundNewsApp/
|
|-- App/
|   |-- BackgroundNewsApp.swift
|   |-- AppDelegate.swift
|
|-- Models/
|   |-- Article.swift
|
|-- Services/
|   |-- NewsService.swift
|   |-- BackgroundTaskManager.swift
|
|-- Storage/
|   |-- NewsStorage.swift
|
|-- Views/
|   |-- ContentView.swift
|   |-- ArticleRowView.swift
|
|-- Info.plist

Expected Learning Outcome

After completing this project, you should understand how to configure background capabilities, register task identifiers, schedule refresh requests, perform asynchronous work, handle task expiration, save application data, and test background execution.

21. Common Mistakes to Avoid

  • Assuming that a scheduled task will run at an exact time.
  • Forgetting to add task identifiers to Info.plist.
  • Registering task handlers too late during application startup.
  • Using BGAppRefreshTask for heavy, long-running processing.
  • Failing to implement an expiration handler.
  • Forgetting to call setTaskCompleted(success:).
  • Leaving long-running operations without cancellation support.
  • Assuming background tasks continue indefinitely after the application is terminated.
  • Performing large file transfers using an unsuitable background execution approach.
  • Failing to persist important progress before a task is interrupted.

22. Interview Questions and Answers

Q1. What is the BackgroundTasks framework in iOS?

Answer: BackgroundTasks is an Apple framework that allows applications to request system-managed background execution for tasks such as refreshing content and performing maintenance operations.

Q2. What is BGTaskScheduler?

Answer: BGTaskScheduler is the central class used to register background task handlers and submit task requests.

Q3. What is BGAppRefreshTask?

Answer: BGAppRefreshTask represents a short background operation used to refresh application content, such as retrieving updated news or account information.

Q4. What is BGProcessingTask?

Answer: BGProcessingTask is designed for longer background operations, including database maintenance, data processing, and application cleanup.

Q5. What is the purpose of BGTaskSchedulerPermittedIdentifiers?

Answer: It is an Info.plist key containing the list of background task identifiers that the application is permitted to register and schedule.

Q6. What does earliestBeginDate do?

Answer: It specifies the earliest date and time when a background task request becomes eligible to run. It does not guarantee execution at that exact time.

Q7. What is an expiration handler?

Answer: An expiration handler is a closure called by the system when a running background task is about to expire. It allows the application to cancel ongoing work and clean up resources.

Q8. Why should a background task call setTaskCompleted(success:)?

Answer: It informs the operating system that the task has finished and reports whether the operation succeeded.

Q9. Can an iOS background task run indefinitely?

Answer: No. Background execution is controlled by the operating system and depends on task type, device conditions, and available resources.

Q10. What is the difference between BGAppRefreshTask and BGProcessingTask?

Answer: BGAppRefreshTask is designed for short content updates, while BGProcessingTask is intended for longer maintenance and processing operations.

Q11. Why might a background task not execute immediately?

Answer: iOS schedules background work according to system conditions, battery usage, device activity, and application usage patterns. A submitted request is not an exact-time appointment.

Q12. What is BGContinuedProcessingTask?

Answer: It is an API available on supported newer iOS versions for certain user-initiated foreground operations that can continue after the application moves into the background.

23. Practical Exercises

  1. Create a SwiftUI application that registers a BGAppRefreshTask.
  2. Add a permitted task identifier to Info.plist.
  3. Schedule an app refresh request using BGAppRefreshTaskRequest.
  4. Create a function that fetches data from a sample REST API.
  5. Save fetched information into local application storage.
  6. Register a BGProcessingTask for database maintenance.
  7. Configure a processing task to require external power.
  8. Implement an expiration handler that cancels an operation.
  9. Test background task execution using Xcode debugging tools.
  10. Build a background news refresh application and document its execution flow.

24. Quick Revision Notes

Concept Quick Explanation
BackgroundTasks Framework for system-managed background execution.
BGTaskScheduler Registers and schedules background tasks.
BGAppRefreshTask Used for short content refresh operations.
BGProcessingTask Used for longer maintenance and processing operations.
BGTaskRequest Represents a request for background execution.
earliestBeginDate Defines the earliest eligible execution time.
Expiration Handler Handles cancellation when task time expires.
setTaskCompleted() Reports task completion to the system.
Info.plist Stores permitted background task identifiers.
Background Modes Enables the background capabilities required by the app.
BGContinuedProcessingTask Supports eligible user-initiated work that continues in the background on supported systems.

25. Conclusion

Implementing background tasks using the BackgroundTasks framework is an important part of building reliable iOS applications. It allows developers to request opportunities for content refresh, data synchronization, and maintenance while respecting the operating system's execution limits.

By understanding BGTaskScheduler, BGAppRefreshTask, BGProcessingTask, task registration, scheduling, expiration handling, and completion reporting, developers can build applications that keep information updated without wasting system resources.

The most important principle is to design background operations that are efficient, cancellable, and safe to resume. Since iOS controls when scheduled tasks execute, applications should never depend on background execution happening at an exact time.

Additional Learning Resources

Previous Next
whatsapp