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

feat: Add immediate:boolean to RunForkOptions #1896

Merged

Conversation

TylorS
Copy link
Contributor

@TylorS TylorS commented Jan 10, 2024

Type

  • Refactor
  • Feature
  • Bug Fix
  • Optimization
  • Documentation Update

Description

  • Adds immediate: boolean to RunForkOptions to enable creating a Fiber which uses fiberRuntime.start() or fiberRuntime.resume()

  • Adds RunCallbackOptions<E, A> which extends RunForkOptions with an onExit callback, such that runCallback has access to the same fork options as runFork.

Related

  • Related Issue #
  • Closes #

Copy link

changeset-bot bot commented Jan 10, 2024

🦋 Changeset detected

Latest commit: 426bdbb

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 17 packages
Name Type
effect Minor
@effect/cli Major
@effect/experimental Major
@effect/opentelemetry Major
@effect/platform-browser Major
@effect/platform-bun Major
@effect/platform-node Major
@effect/platform Major
@effect/printer-ansi Major
@effect/printer Major
@effect/rpc-http-node Major
@effect/rpc-http Major
@effect/rpc-nextjs Major
@effect/rpc-workers Major
@effect/rpc Major
@effect/schema Major
@effect/typeclass Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@mattiamanzati
Copy link
Contributor

Bonus, could we please have this also on unsafeRunCallback? It is useful to have the callback eventually be called synchronously if the effect is sync as well

@TylorS
Copy link
Contributor Author

TylorS commented Jan 11, 2024

@mattiamanzati I should be able to add the immediate flag there as well. I'm going to remove the Scope option though, as it could lead to memory leaks if the surrounding scope is open indefinitely as the Fiber is never removed from the Scope upon exiting

@TylorS TylorS force-pushed the ts/feat/additional-runForkOptions branch 2 times, most recently from 917105e to 67952ee Compare January 11, 2024 16:47
@TylorS TylorS marked this pull request as ready for review January 11, 2024 16:49
@TylorS
Copy link
Contributor Author

TylorS commented Jan 11, 2024

@mattiamanzati Updated in the latest pushes

@mattiamanzati
Copy link
Contributor

@TylorS Thanks 🙏
Can't wait for this PR to be accepted and released!

@mikearnaldi
Copy link
Member

@mattiamanzati I should be able to add the immediate flag there as well. I'm going to remove the Scope option though, as it could lead to memory leaks if the surrounding scope is open indefinitely as the Fiber is never removed from the Scope upon exiting

Why would the fiber not being removed upon exit? that should be the behaviour

@TylorS
Copy link
Contributor Author

TylorS commented Jan 11, 2024

@mikearnaldi When you do Scope.addFinalizer(scope, Fiber.interrupt(fiber)), there is no corresponding API for removing the finalizer from the Scope after the Fiber exits. So if the scope it is being added to lives indefinitely (i.e. the scope of a React component's event listeners), the Fibers will be unable to be garbage collected due to being kept within the open Scope.

@mikearnaldi
Copy link
Member

@mikearnaldi When you do Scope.addFinalizer(scope, Fiber.interrupt(fiber)), there is no corresponding API for removing the finalizer from the Scope after the Fiber exits. So if the scope it is being added to lives indefinitely (i.e. the scope of a React component's event listeners), the Fibers will be unable to be garbage collected due to being kept within the open Scope.

you're right, I will investigate if adding an api to remove a finaliser may be useful

@TylorS
Copy link
Contributor Author

TylorS commented Jan 11, 2024

In the same vein, I'm not positive that forkIn or forkScoped are entirely safe. They do utilize forked Scope's which allows the Fiber to be garbage collected after completion, but there's a (albeit smaller) memory leak of child scopes if the parent scope is kept open indefinitely.

@TylorS TylorS changed the title feat: Add immediate:boolean & scope:Scope to RunForkOptions feat: Add immediate:boolean to RunForkOptions Jan 11, 2024
@mikearnaldi
Copy link
Member

/** @internal */
export const forkIn = dual<
  (scope: Scope.Scope) => <R, E, A>(self: Effect.Effect<R, E, A>) => Effect.Effect<R, never, Fiber.RuntimeFiber<E, A>>,
  <R, E, A>(self: Effect.Effect<R, E, A>, scope: Scope.Scope) => Effect.Effect<R, never, Fiber.RuntimeFiber<E, A>>
>(
  2,
  (self, scope) =>
    core.uninterruptibleMask((restore) =>
      core.flatMap(scope.fork(executionStrategy.sequential), (child) =>
        pipe(
          restore(self),
          core.onExit((exit) => child.close(exit)),
          fiberRuntime.forkDaemon,
          core.tap((fiber) =>
            child.addFinalizer(() =>
              core.fiberIdWith((fiberId) =>
                Equal.equals(fiberId, fiber.id()) ?
                  core.unit :
                  core.asUnit(core.interruptFiber(fiber))
              )
            )
          )
        ))
    )
)

This is safe, it forks a separate scope and that scope is closed as the fiber ends

@TylorS
Copy link
Contributor Author

TylorS commented Jan 11, 2024

But closing that child/forked Scope doesn't remove its reference as a Finalizer in the parent Scope when it is closed

@TylorS
Copy link
Contributor Author

TylorS commented Jan 11, 2024

I take that back, I found the code that keeps it safe here - https://github.com/Effect-TS/effect/blob/main/packages/effect/src/internal/fiberRuntime.ts#L2962

@TylorS TylorS force-pushed the ts/feat/additional-runForkOptions branch from 67952ee to 16bce8c Compare January 12, 2024 03:31
@github-actions github-actions bot changed the base branch from main to next-minor January 12, 2024 03:32
@tim-smart tim-smart self-requested a review January 12, 2024 03:51
@tim-smart
Copy link
Member

Bonus, could we please have this also on unsafeRunCallback? It is useful to have the callback eventually be called synchronously if the effect is sync as well

The current behaviour is to start immediately, so you will see no change with this PR.

@mattiamanzati
Copy link
Contributor

Bonus, could we please have this also on unsafeRunCallback? It is useful to have the callback eventually be called synchronously if the effect is sync as well

The current behaviour is to start immediately, so you will see no change with this PR.

Uhm but run callback relies on run fork, so it should be affected as well right?

@TylorS
Copy link
Contributor Author

TylorS commented Jan 12, 2024

This PR enables non-immediate starts through immediate:false as the default is true to avoid breaking changes

@mattiamanzati
Copy link
Contributor

enables

Ohh, I though of it in the completely opposite direction.

@mikearnaldi
Copy link
Member

Can we add back Scope in the style used by forkIn? also it is worth updating the main runFork method in Effect.ts to take the RunOptions currently only Runtime exposes it

@TylorS
Copy link
Contributor Author

TylorS commented Jan 14, 2024

@mikearnaldi PR Updated with Scope here and the additional options to Effect.runFork here

@github-actions github-actions bot force-pushed the next-minor branch 3 times, most recently from f723296 to ff47da4 Compare January 15, 2024 02:38
@tim-smart
Copy link
Member

@TylorS if you rebase that should fix CI

@TylorS TylorS force-pushed the ts/feat/additional-runForkOptions branch from 8215ce6 to 426bdbb Compare January 15, 2024 03:18
@TylorS
Copy link
Contributor Author

TylorS commented Jan 15, 2024

Rebased

@tim-smart tim-smart merged commit ccf2fc3 into Effect-TS:next-minor Jan 15, 2024
9 checks passed
@github-actions github-actions bot mentioned this pull request Jan 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

4 participants