Skip to content

Mutex lock on flush#36

Merged
matsumo0922 merged 5 commits intomainfrom
fix-crush2
Jul 17, 2025
Merged

Mutex lock on flush#36
matsumo0922 merged 5 commits intomainfrom
fix-crush2

Conversation

@matsumo0922
Copy link
Copy Markdown
Member

@matsumo0922 matsumo0922 commented Jul 17, 2025

Related links

  • engineering/issues/3220

Why?

  • engineering/issues/3220

How?

  • flush が二重に走ることのないように、mutex でロックします

Testing 🔍

  • demo アプリを起動して、SendLog の通信中に flush を明示的に呼んでも二重に呼ばれないことを確認してください。

matsumo0922 and others added 3 commits July 17, 2025 00:16
This change allows PureeLogger to operate without a lifecycle, which is primarily relevant for iOS where a default lifecycle isn't always available or necessary.

On Android, PureeLogger continues to use ProcessLifecycleOwner by default.

Key changes:
- `DefaultLifecycleOwner` has been removed.
- `PureeLogger` now accepts a nullable `Lifecycle`. If null, it immediately calls `resume()`.
- The iOS `Puree.build()` method now passes `null` for the lifecycle.
- The Android `Puree` constructor now directly uses `ProcessLifecycleOwner.get().lifecycle`.
- `PureeBufferedOutput.resume()` is now a suspend function and uses a Mutex for `requestFlush` to prevent concurrent flush operations.
- Updated iOS sample app:
    - Added a "Flush!" button to manually trigger flushing.
    - Modified `OSLogBufferedOutput` to simulate a delay in `emit` for testing purposes.
    - Adjusted `AddTimeFilter` to include fractional seconds in the timestamp.
This commit refactors how CoroutineScope is created and used within `PureeLogger` and `PureeBufferedOutput`.

- `PureeLogger`:
    - Now directly accepts a `CoroutineContext` (renamed from `dispatcher`) in its constructor.
    - The internal `scope` is initialized directly with this context.
    - The `CoroutineExceptionHandler` and `SupervisorJob` are now configured at the platform-specific `Puree` builder level (`Puree.android.kt` and `Puree.ios.kt`) and passed into `PureeLogger`.
- `PureeBufferedOutput`:
    - The `initialize` method now accepts a `CoroutineScope` directly instead of a `CoroutineContext`.
    - This simplifies the initialization as the `CoroutineExceptionHandler` and `SupervisorJob` are now handled by the `CoroutineScope` provided by `PureeLogger`.

This change aims to centralize the CoroutineScope configuration at the builder level, making the core components more focused on their specific responsibilities and improving testability by allowing injection of a pre-configured scope.
@matsumo0922 matsumo0922 self-assigned this Jul 17, 2025
@matsumo0922 matsumo0922 requested a review from a team as a code owner July 17, 2025 08:51
@matsumo0922 matsumo0922 requested a review from Narachii July 17, 2025 08:51
* @see resume
*/
internal suspend fun requestFlush() {
internal suspend fun requestFlush() = flushMutex.withLock {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mutex を用いて二重に呼ばれないように調整します。

coroutineScope.launch {
internal suspend fun resume() {
workerJob?.cancelAndJoin()
workerJob = coroutineScope.launch {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resume が二重に呼ばれないようにも調整します

)
if (lifecycle != null) {
lifecycle.addObserver(
object : DefaultLifecycleObserver {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iOS で onResume を返すだけの LifecycleOwner を作って使用していましたが、これが悪さしている可能性をなくすため、nullable にして ios では null を渡すようにしています。

internal var dispatcher: CoroutineDispatcher = newSingleThreadContext("PureeLogger")
internal val dispatcher = newSingleThreadContext("PureeLogger")
.plus(SupervisorJob())
.plus(
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dispatcher を puree 全体で統一しています

This commit introduces a new output class, `PurgeableOSLogWarningBufferedOutput`, specifically for `PeriodicLog` types.

Additionally, comments were updated in `OSLogBufferedOutput.swift` and minor formatting adjustments were made in `AddTimeFilter.swift`.
internal fun resume() {
coroutineScope.launch {
internal suspend fun resume() {
workerJob?.cancelAndJoin()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resume はどのスレッドから呼ばれる想定ですか?
もしメインスレッドで実行されていた場合、 cancelAndJoin によって workerJob が完了するまでメインスレッドをブロックしないか少し心配しています。

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/new-single-thread-context.html によると、newSingleThreadContext は占有のスレッドを新しく立ち上げて用いるようです。

そのためスレッドプールも IO や Main とは異なり、メインスレッドが割り当てられることはありません。

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

良さそう。調査ありがとうございました。

Copy link
Copy Markdown
Member

@koyama-kani-daisuki koyama-kani-daisuki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 🙆

@matsumo0922
Copy link
Copy Markdown
Member Author

レビューありがとうございました 🙏

@matsumo0922 matsumo0922 merged commit 261b77e into main Jul 17, 2025
2 checks passed
@matsumo0922 matsumo0922 deleted the fix-crush2 branch July 17, 2025 10:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants