• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Unleash / unleash-android / 38719019292
84%

Build:
DEFAULT BRANCH: main
Ran 15 Oct 2026 10:19AM UTC
Jobs 1
Files 27
Run time 1min
Badge
Embed ▾
README BADGES
x

If you need to use a raster PNG badge, change the '.svg' to '.png' in the link

Markdown

Textile

RDoc

HTML

Rst

15 Oct 2026 10:15AM UTC coverage: 83.542% (+1.6%) from 81.912%
38719019292

push

github

web-flow
fix: scope `close()` to the instance instead of the whole process (#152)

fix: scope close() to the instance instead of the whole process

## Issue
Working at [OF-provider issue with start()](https://github.com/Unleash/unleash-openfeature-android-provider/pull/4), we noticed that:

`unleash-openfeature-android-provider` calls `close()` from its `shutdown()` ...but
when we create an Unleash client, close it, then create another one. The 2nd client **never** works - no flags, no fetching, no error. Every lookup returns the fallback value ..._forever_.

e.g.
```kotlin
val first = DefaultUnleash(context, config)
first.start()
first.close()

val second = DefaultUnleash(context, config)
second.start()
// second.isReady() is false, and stays false. No exception. Nothing in logcat.
```

#### Whom affects? 
anything that creates a client, closes it, and creates another one in the same process:
- apps that re-initialise on logout/login.
- providers like `unleash-openfeature-android-provider` which calls `close()` from its `shutdown()`.
- test suites that set up and tear down per test. The 2nd test onwards silently gets a dead client.


### Why it happens

the SDK has exactly one Job for the entire app:
```kotlin
// DefaultUnleash.kt
private val job = SupervisorJob()
val unleashScope = CoroutineScope(Dispatchers.Default + job + unleashExceptionHandler)
```

there is one instance of it per process, shared by every client the SDK creates. And `close()` ends with:

```kotlin
job.cancel("Unleash received closed signal")
```

So **closing one client** **flips the whole library**. The 1st client shut down correctly - but so did the Job _every_ future client depends on.

That's why the 2nd client fails silently rather than crashing: `start()` calls `coroutineScope.launch { readyOnFeaturesReceived() }`, the launch is a no-op on a cancelled Job, so nothing fetches, nothing lands in the cache, `ready` is always 'unknown' :/ 

## The fix

We now give each client its own Jo... (continued)

273 of 376 branches covered (72.61%)

Branch coverage included in aggregate %.

22 of 26 new or added lines in 3 files covered. (84.62%)

84 existing lines in 7 files now uncovered.

864 of 985 relevant lines covered (87.72%)

5.64 hits per line

Jobs
ID Job ID Ran Files Coverage
1 38719019292.1 15 Oct 2026 10:19AM UTC 27
83.54
GitHub Action Run
Source Files on build 38719019292
  • Tree
  • List 27
  • Changed 26
  • Source Changed 25
  • Coverage Changed 26
Coverage ∆ File Lines Relevant Covered Missed Hits/Line Branch Hits Branch Misses
  • Back to Repo
  • Github Actions Build #38719019292
  • 4d78f5a2 on github
  • Prev Build on main (#14127381157)
  • Next Build on main (#38727910452)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc