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

refactor: Remove pipeline abstraction #144

Merged
merged 8 commits into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions src/HttpHandler/Builder.fs → src/Builder.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

namespace Oryx

open Oryx.Pipeline

type RequestBuilder() =
member _.Zero() : HttpHandler<unit> = httpRequest
Expand All @@ -12,14 +11,14 @@ type RequestBuilder() =
member _.Return(content: 'TResult) : HttpHandler<'TResult> = singleton content
member _.ReturnFrom(req: HttpHandler<'TResult>) : HttpHandler<'TResult> = req
member _.Delay(fn) = fn ()
member _.Combine(source, other) = source |> Core.bind (fun _ -> other)
member _.Combine(source, other) = source |> bind (fun _ -> other)

member _.For(source: 'TSource seq, func: 'TSource -> HttpHandler<'TResult>) : HttpHandler<'TResult list> =
source |> Seq.map func |> sequential

/// Binds value of 'TValue for let! All handlers runs in same context within the builder.
member _.Bind(source: HttpHandler<'TSource>, fn: 'TSource -> HttpHandler<'TResult>) : HttpHandler<'TResult> =
source |> Core.bind fn
source |> bind fn

[<AutoOpen>]
module Builder =
Expand Down
19 changes: 19 additions & 0 deletions src/Core.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright 2020 Cognite AS
// SPDX-License-Identifier: Apache-2.0

namespace Oryx

open System.Threading.Tasks

type IHttpNext<'TSource> =
abstract member OnSuccessAsync: ctx: HttpContext * content: 'TSource -> Task<unit>
abstract member OnErrorAsync: ctx: HttpContext * error: exn -> Task<unit>
abstract member OnCancelAsync: ctx: HttpContext -> Task<unit>

type HttpHandler<'TResult> = IHttpNext<'TResult> -> Task<unit>

exception HttpException of (HttpContext * exn) with
override this.ToString() =
match this :> exn with
| HttpException(_, err) -> err.ToString()
| _ -> failwith "This should not never happen."
58 changes: 25 additions & 33 deletions src/Pipeline/Error.fs → src/Error.fs
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
// Copyright 2020 Cognite AS
// SPDX-License-Identifier: Apache-2.0

namespace Oryx.Pipeline
namespace Oryx

open System

open FSharp.Control.TaskBuilder
open Oryx

module Error =
/// Handler for protecting the pipeline from exceptions and protocol violations.
let protect<'TContext, 'TSource> (source: Pipeline<'TContext, 'TSource>) : Pipeline<'TContext, 'TSource> =
/// Handler for protecting the HttpHandler from exceptions and protocol violations.
let protect<'TSource> (source: HttpHandler<'TSource>) : HttpHandler<'TSource> =
fun next ->
let mutable stopped = false

{ new IAsyncNext<'TContext, 'TSource> with
{ new IHttpNext<'TSource> with
member _.OnSuccessAsync(ctx, content) =
task {
match stopped with
Expand Down Expand Up @@ -47,12 +46,12 @@ module Error =
|> source

/// Handler for catching errors and then delegating to the error handler on what to do.
let catch<'TContext, 'TSource>
(errorHandler: 'TContext -> exn -> Pipeline<'TContext, 'TSource>)
(source: Pipeline<'TContext, 'TSource>)
: Pipeline<'TContext, 'TSource> =
let catch<'TSource>
(errorHandler: HttpContext -> exn -> HttpHandler<'TSource>)
(source: HttpHandler<'TSource>)
: HttpHandler<'TSource> =
fun next ->
{ new IAsyncNext<'TContext, 'TSource> with
{ new IHttpNext<'TSource> with
member _.OnSuccessAsync(ctx, content) =
task {
try
Expand All @@ -66,7 +65,6 @@ module Error =
match err with
| PanicException error -> return! next.OnErrorAsync(ctx, error)
| _ -> do! (errorHandler ctx err) next

}

member _.OnCancelAsync(ctx) = next.OnCancelAsync(ctx) }
Expand All @@ -79,22 +77,22 @@ module Error =
| Error
| Panic

/// Choose from a list of pipelines to use. The first middleware that succeeds will be used. Handlers will be
/// Choose from a list of HttpHandlers to use. The first middleware that succeeds will be used. Handlers will be
/// tried until one does not produce any error, or a `PanicException`.
let choose<'TContext, 'TSource, 'TResult>
(handlers: (Pipeline<'TContext, 'TSource> -> Pipeline<'TContext, 'TResult>) list)
(source: Pipeline<'TContext, 'TSource>)
: Pipeline<'TContext, 'TResult> =
let choose<'TSource, 'TResult>
(handlers: (HttpHandler<'TSource> -> HttpHandler<'TResult>) list)
(source: HttpHandler<'TSource>)
: HttpHandler<'TResult> =
fun next ->
let exns: ResizeArray<exn> = ResizeArray()

{ new IAsyncNext<'TContext, 'TSource> with
{ new IHttpNext<'TSource> with
member _.OnSuccessAsync(ctx, content) =
let mutable state = ChooseState.Error

task {
let obv =
{ new IAsyncNext<'TContext, 'TResult> with
{ new IHttpNext<'TResult> with
member _.OnSuccessAsync(ctx, content) =
task {
exns.Clear() // Clear to avoid buildup of exceptions in streaming scenarios.
Expand All @@ -106,10 +104,10 @@ module Error =
member _.OnErrorAsync(_, error) =
task {
match error, state with
| PanicException(_), st when st <> ChooseState.Panic ->
| PanicException _, st when st <> ChooseState.Panic ->
state <- ChooseState.Panic
return! next.OnErrorAsync(ctx, error)
| SkipException(_), st when st = ChooseState.NoError ->
| SkipException _, st when st = ChooseState.NoError ->
// Flag error, but do not record skips.
state <- ChooseState.Error
| _, ChooseState.Panic ->
Expand All @@ -122,7 +120,7 @@ module Error =

member _.OnCancelAsync(ctx) = next.OnCancelAsync(ctx) }

/// Proces handlers until `NoError` or `Panic`.
// Process handlers until `NoError` or `Panic`.
for handler in handlers do
if state = ChooseState.Error then
state <- ChooseState.NoError
Expand All @@ -134,9 +132,9 @@ module Error =
()
| ChooseState.Error, exns when exns.Count > 1 ->
return! next.OnErrorAsync(ctx, AggregateException(exns))
| ChooseState.Error, exns when exns.Count = 1 -> return! next.OnErrorAsync(ctx, exns.[0])
| ChooseState.Error, exns when exns.Count = 1 -> return! next.OnErrorAsync(ctx, exns[0])
| ChooseState.Error, _ ->
return! next.OnErrorAsync(ctx, SkipException "Choose: No hander matched")
return! next.OnErrorAsync(ctx, SkipException "Choose: No handler matched")
| ChooseState.NoError, _ -> ()
}

Expand All @@ -151,25 +149,19 @@ module Error =
|> source

/// Error handler for forcing error. Use with e.g `req` computational expression if you need to "return" an error.
let fail<'TContext, 'TSource, 'TResult>
(err: Exception)
(source: Pipeline<'TContext, 'TSource>)
: Pipeline<'TContext, 'TResult> =
let fail<'TSource, 'TResult> (err: Exception) (source: HttpHandler<'TSource>) : HttpHandler<'TResult> =
fun next ->
{ new IAsyncNext<'TContext, 'TSource> with
{ new IHttpNext<'TSource> with
member _.OnSuccessAsync(ctx, content) = next.OnErrorAsync(ctx, err)
member _.OnErrorAsync(ctx, exn) = next.OnErrorAsync(ctx, exn)
member _.OnCancelAsync(ctx) = next.OnCancelAsync(ctx) }
|> source

/// Error handler for forcing a panic error. Use with e.g `req` computational expression if you need break out of
/// the any error handling e.g `choose` or `catch`•.
let panic<'TContext, 'TSource, 'TResult>
(err: Exception)
(source: Pipeline<'TContext, 'TSource>)
: Pipeline<'TContext, 'TResult> =
let panic<'TSource, 'TResult> (err: Exception) (source: HttpHandler<'TSource>) : HttpHandler<'TResult> =
fun next ->
{ new IAsyncNext<'TContext, 'TSource> with
{ new IHttpNext<'TSource> with
member _.OnSuccessAsync(ctx, content) =
next.OnErrorAsync(ctx, PanicException(err))

Expand Down
File renamed without changes.
2 changes: 0 additions & 2 deletions src/HttpHandler/Fetch.fs → src/Fetch.fs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ open System.Net.Http.Headers
open System.Web

open FSharp.Control.TaskBuilder
open Oryx.Pipeline

[<AutoOpen>]
module Fetch =
Expand Down Expand Up @@ -101,7 +100,6 @@ module Fetch =
response.Content
)


response.Dispose()
return result
with ex when not (ex :? HttpException) ->
Expand Down
File renamed without changes.
File renamed without changes.
Loading