Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pausing Database Observation When App is Backgrounded #1704

Closed
markst opened this issue Jan 25, 2025 · 2 comments
Closed

Pausing Database Observation When App is Backgrounded #1704

markst opened this issue Jan 25, 2025 · 2 comments
Labels

Comments

@markst
Copy link

markst commented Jan 25, 2025

Our app uses GRDB for database observation, particularly with DatabaseRegionObservation to manage back pressure as mentioned in #966. However, since we also enable background audio modes, our app continues observing the database while in the background. This results in significant CPU usage, which negatively impacts battery life for our users.

We’re considering an approach where we dynamically pause or resume database observation based on the app’s background state. Here’s a simplified example of how the Publisher might look:

let appStatePublisher = NotificationCenter.default.publisher(for: UIApplication.didEnterBackgroundNotification)
    .merge(with: NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification))
    .map { notification in
        notification.name == UIApplication.didEnterBackgroundNotification
    }
    .removeDuplicates()

appStatePublisher
    .flatMapLatest { isBackgrounded in
        isBackgrounded ? 
            Empty().eraseToAnyPublisher() : 
            DatabaseRegionObservation(
                tracking: fetchRequest(ids: ids, filters: filters, limit: limit)
            )
            .publisher(in: databaseWriter)
            .map { _ in }
            .throttle(for: .seconds(throttle), scheduler: queue, latest: true)
            .prepend(())
            .map {
                databaseWriter.readPublisher {
                    try fetchRequest(ids: ids, filters: filters, limit: limit)
                        .fetchAll($0)
                }
            }
            .switchToLatest()
            .eraseToAnyPublisher()
    }

In this approach, observation is paused when the app transitions to the background and resumed when it returns to the foreground.

Would you recommend this approach? Is this in line with GRDB's capabilities, or is there a more efficient way to achieve this?

@groue
Copy link
Owner

groue commented Jan 25, 2025

Hello @markst,

I see nothing wrong in your sample code. I did not run it, but it looks like it does what you say it should do.

Is this in line with GRDB's capabilities?

Yes, sure. You observe transactions, you fetch later, you stop observing, no problem. You can add a few print to your publishers if you want to check the runtime behavior.

I like the .map { _ in }. It drops the Database connection before switching to queue, where the connection can not (and must not) be used:

.map { _ in /* Drop the connection before leaving the database writer dispatch queue */ }

is there a more efficient way to achieve this?

I'm not sure I see the efficiency problem you are referring to.

@groue groue added the support label Jan 25, 2025
@groue
Copy link
Owner

groue commented Jan 29, 2025

No news is good news: I suppose your app is working as expected. Happy GRDB!

@groue groue closed this as completed Jan 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants