Search code examples
typescriptfunctional-programmingfp-tseffect-ts

Track process during Effect.all


Currently I'm using Effect-Ts to perform multiple operations (promises) with some concurrency level using Effect.all.

Here the very basic code:

async function method<R>(
  fn: (() => Promise<R>)[],
  concurrency: number,
) {
  const tasks = fn.map(c =>
    Effect.promise(c)
  )

  let effect = Effect.all(tasks, {
    concurrency: concurrency,
  })
  
  const results = await Effect.runPromise(effect)
  return results
}

I want to track the process and have a sort of progress bar like this:

Progress: 1/100
Progress: 2/100
...
Progress: 100/100

I've tried (and read) multiple stuff but I haven't been able to achieve what I wanted.
What is the most appropriate way to handle this need?

Many thx.


Solution

  • Ok here's how I've solved it.
    I'm not sure if it can be considered pure functional programming since I'm modifying the progress variable but it worked for my need.

    *Note that I've avoided printing logs for every Promise resolution instead I've used ticks to limit the "noise"

    const options = {
      totalTicks: 15,
      onNewTicks: (index: number, total: number) => console.log(`Fetching chunk ${index + 1} of ${total} (${Math.floor((index / total) * 100)}%)`),
      concurrency: 5
    }
    
    const executeTasks = <A>(
      tasks: ReadonlyArray<Task<A>>
    ) => {
      let progress = 0
      let ticks = tasks.length / options.totalTicks
      let currentTick = 0
      const effects = tasks.map(c =>
        pipe(
          Effect.promise(c),
          Effect.tap(() => {
            progress++
            if (progress / ticks > currentTick) {
              return options.onNewTicks(currentTick++, options.totalTicks)
            }
          }),
        ),
      )
    
      return Effect.all(effects, {
          concurrency: options.concurrency,
      })
    }
    

    Here is the full working example