網站搜尋

typescript - 並行執行一個 TaskEithers 陣列,但如果一個或多個任務失敗仍然繼續


我必須並行地建立一個 IO 調用的陣列,並在成功時合併調用的內容。如果其中一個失敗,其他的將照常處理,但會顯示錯誤訊息。

我對於這個如何實施的思考過程:

Array<TE<E, A>> -> TE<E, Array<A>> -> TE<E, MergedA> -> [E, A]

我目前正在做的事:

我目前正在對一組TE進行排序,但鏈中的任何故障都會產生一個左邊。

pipe(
sequenceT(TE.taskEither)(arrayofTE), //TE<E,A>[] -> TE<E,A[]>
TE.map(mergeFn), //TE<E, A[]> -> TE<E, MergedA> 
???
)

我該如何阻止短路?

答案#1

你可以將 T.task 傳遞給 sequence/sequenceT,而不是 TE.taskEither(文件):

操作:並行執行一系列任務,收集所有失敗和成功

TaskEither: array.sequence(T.task)(taskEithers) - 對 sequenceT 也一樣

sequence:並行執行相同類型的任務

import { pipeable as P, taskEither as TE, task as T, array as A, either as E } from "fp-ts";

const arrayofTE: TE.TaskEither<string, number>[] = [
  TE.right(1),
  TE.right(2),
  TE.left("Oh shit")
];

const run = P.pipe(
  // change to T.task instead of TE.taskEither here
  A.array.sequence(T.task)(arrayofTE),
  mergeFn
);

run(); // run side effect
// returns Promise<{"errors":["Oh shit"],"results":[1,2]}>

// whatever merged result you want to have; this one collects all errors and all results
declare function mergeFn(te: T.Task<E.Either<string, number>[]>): T.Task<Results> 

type Results = { errors: string[]; results: number[] };

sequenceT:以並行方式運行不同類型的任務

import { apply as AP /* and others above */ } from "fp-ts";

// Here, TaskEither result can be number | boolean (success case), string on error
const arrayofTE = [TE.right(1), TE.right(true), TE.left("Oh shit")] as const;

const run = P.pipe(
  AP.sequenceT(T.task)(...arrayofTE), // we use sequenceT here and pass T.task again
  mergeFn
);

declare function mergeFn(a: T.Task<E.Either<string, number | boolean>[]>): T.Task<Results>

這裡有一些帶有 mergeFn 實現的沙盒可以玩:sequence,sequenceT。

答案#2

使用 fp-ts 2.16.1 的 sequenceT,其中 TE.taskStream 已被棄用

import { sequenceT } from "fp-ts/lib/Apply.js"
import * as TE from "fp-ts/lib/TaskEither.js"

await pipe(
    sequenceT(TE.ApplyPar)(
      checkAuth(event),
      getDocs(event),
    ),
    TE.map(([auth, docs]) => {
      if (!auth) throw new Error("Unauthorized")
      return docs
    }),
    TE.map(flattenDocs),
)()