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

Preserve Span on Interruption #3578

Draft
wants to merge 15 commits into
base: next-minor
Choose a base branch
from
Draft
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: 5 additions & 0 deletions .changeset/eighty-lobsters-refuse.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"effect": minor
---

Made `Ref`, `SynchronizedRed` and `SubscriptionRef` a subtype of `Effect`
16 changes: 16 additions & 0 deletions .changeset/gorgeous-toes-help.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
"effect": minor
---

The `Deferred<A>` is now a subtype of `Effect<A>`. This change simplifies handling of deferred values, removing the need for explicit call `Deffer.await`.

```typescript
import { Effect, Deferred } from "effect"

Effect.gen(function* () {
const deferred = yield* Deferred.make<string>()

const before = yield* Deferred.await(deferred)
const after = yield* deferred
})
```
6 changes: 6 additions & 0 deletions .changeset/honest-cups-wash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"effect": minor
"@effect/platform": patch
---

add Logger.prettyLoggerDefault, to prevent duplicate pretty loggers
6 changes: 6 additions & 0 deletions .changeset/quick-roses-warn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"effect": minor
"@effect/cli": patch
---

Add Number.round
16 changes: 16 additions & 0 deletions .changeset/seven-lamps-nail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
"effect": minor
---

The `Fiber<A, E>` is now a subtype of `Effect<A, E>`. This change removes the need for explicit call `Fiber.join`.

```typescript
import { Effect, Fiber } from "effect"

Effect.gen(function*() {
const fiber = yield* Effect.fork(Effect.succeed(1))

const oldWay = yield* Fiber.join(fiber)
const now = yield* fiber
}))
```
10 changes: 10 additions & 0 deletions .changeset/stream-share.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"effect": minor
---

add `Stream.share` api

The `Stream.share` api is a ref counted variant of the broadcast apis.

It allows you to share a stream between multiple consumers, and will close the
upstream when the last consumer ends.
87 changes: 87 additions & 0 deletions .changeset/tender-foxes-walk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
---
"@effect/platform-browser": minor
"@effect/platform-node": minor
"@effect/platform-bun": minor
"@effect/platform": minor
"@effect/rpc-http": minor
---

refactor /platform HttpClient

#### HttpClient.fetch removed

The `HttpClient.fetch` client implementation has been removed. Instead, you can
access a `HttpClient` using the corresponding `Context.Tag`.

```ts
import { FetchHttpClient, HttpClient } from "@effect/platform"
import { Effect } from "effect"

Effect.gen(function* () {
const client = yield* HttpClient.HttpClient

// make a get request
yield* client.get("https://jsonplaceholder.typicode.com/todos/1")
}).pipe(
Effect.scoped,
// the fetch client has been moved to the `FetchHttpClient` module
Effect.provide(FetchHttpClient.layer)
)
```

#### `HttpClient` interface now uses methods

Instead of being a function that returns the response, the `HttpClient`
interface now uses methods to make requests.

Some shorthand methods have been added to the `HttpClient` interface to make
less complex requests easier.

```ts
import {
FetchHttpClient,
HttpClient,
HttpClientRequest
} from "@effect/platform"
import { Effect } from "effect"

Effect.gen(function* () {
const client = yield* HttpClient.HttpClient

// make a get request
yield* client.get("https://jsonplaceholder.typicode.com/todos/1")
// make a post request
yield* client.post("https://jsonplaceholder.typicode.com/todos")

// execute a request instance
yield* client.execute(
HttpClientRequest.get("https://jsonplaceholder.typicode.com/todos/1")
)
})
```

#### Scoped `HttpClientResponse` helpers removed

The `HttpClientResponse` helpers that also eliminated the `Scope` have been removed.

Instead, you can use the `HttpClientResponse` methods directly, and explicitly
add a `Effect.scoped` to the pipeline.

```ts
import { FetchHttpClient, HttpClient } from "@effect/platform"
import { Effect } from "effect"

Effect.gen(function* () {
const client = yield* HttpClient.HttpClient

yield* client.get("https://jsonplaceholder.typicode.com/todos/1").pipe(
Effect.flatMap((response) => response.json),
Effect.scoped // eliminate the `Scope`
)
})
```

#### Some apis have been renamed

Including the `HttpClientRequest` body apis, which is to make them more
discoverable.
5 changes: 5 additions & 0 deletions .changeset/tricky-spoons-wait.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"effect": minor
---

Preserve Span on Interruption
6 changes: 6 additions & 0 deletions .changeset/twelve-dingos-destroy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@effect/opentelemetry": minor
"effect": minor
---

Cache some fiber references in the runtime to optimize reading in hot-paths
26 changes: 26 additions & 0 deletions .changeset/violet-suns-chew.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
"effect": minor
---

Added `RcMap.keys` and `MutableHashMap.keys`.

These functions allow you to get a list of keys currently stored in the underlying hash map.

```ts
const map = MutableHashMap.make([["a", "a"], ["b", "b"], ["c", "c"]])
const keys = MutableHashMap.keys(map) // ["a", "b", "c"]
```

```ts
Effect.gen(function* () {
const map = yield* RcMap.make({
lookup: (key) => Effect.succeed(key)
})

yield* RcMap.get(map, "a")
yield* RcMap.get(map, "b")
yield* RcMap.get(map, "c")

const keys = yield* RcMap.keys(map) // ["a", "b", "c"]
})
```
16 changes: 16 additions & 0 deletions .changeset/wise-kiwis-tan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
"effect": minor
---

The `FiberRef<A>` is now a subtype of `Effect<A>`. This change simplifies handling of deferred values, removing the need for explicit call `FiberRef.get`.

```typescript
import { Effect, FiberRef } from "effect"

Effect.gen(function* () {
const fiberRef = yield* FiberRef.make("value")

const before = yield* FiberRef.get(fiberRef)
const after = yield* fiberRef
})
```
8 changes: 2 additions & 6 deletions packages/cli/src/internal/prompt/number.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as Optimize from "@effect/printer/Optimize"
import * as Schema from "@effect/schema/Schema"
import * as Arr from "effect/Array"
import * as Effect from "effect/Effect"
import * as EffectNumber from "effect/Number"
import * as Option from "effect/Option"
import type * as Prompt from "../../Prompt.js"
import * as InternalPrompt from "../prompt.js"
Expand All @@ -20,11 +21,6 @@ interface State {
readonly error: Option.Option<string>
}

const round = (number: number, precision: number) => {
const factor = Math.pow(10, precision)
return Math.round(number * factor) / factor
}

const parseInt = Schema.NumberFromString.pipe(
Schema.int(),
Schema.decodeUnknown
Expand Down Expand Up @@ -352,7 +348,7 @@ function handleProcessFloat(options: FloatOptions) {
})),
onSuccess: (n) =>
Effect.flatMap(
Effect.sync(() => round(n, options.precision)),
Effect.sync(() => EffectNumber.round(n, options.precision)),
(rounded) =>
Effect.match(options.validate(rounded), {
onFailure: (error) =>
Expand Down
36 changes: 22 additions & 14 deletions packages/cluster-node/examples/sample-connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,25 +30,33 @@ const liveLayer = Effect.gen(function*() {
Layer.effectDiscard,
Layer.provide(Sharding.live),
Layer.provide(StorageFile.storageFile),
Layer.provide(PodsRpc.podsRpc<never>((podAddress) =>
HttpRpcResolver.make<ShardingServiceRpc.ShardingServiceRpc>(
HttpClient.fetchOk.pipe(
HttpClient.mapRequest(
HttpClientRequest.prependUrl(`http://${podAddress.host}:${podAddress.port}/api/rest`)
)
)
).pipe(RpcResolver.toClient)
)),
Layer.provide(ShardManagerClientRpc.shardManagerClientRpc(
(shardManagerUri) =>
Layer.provide(Layer.unwrapEffect(Effect.gen(function*() {
const client = yield* HttpClient.HttpClient
return PodsRpc.podsRpc<never>((podAddress) =>
HttpRpcResolver.make<ShardingServiceRpc.ShardingServiceRpc>(
HttpClient.fetchOk.pipe(
client.pipe(
HttpClient.filterStatusOk,
HttpClient.mapRequest(
HttpClientRequest.prependUrl(shardManagerUri)
HttpClientRequest.prependUrl(`http://${podAddress.host}:${podAddress.port}/api/rest`)
)
)
).pipe(RpcResolver.toClient)
)),
)
}))),
Layer.provide(Layer.unwrapEffect(Effect.gen(function*() {
const client = yield* HttpClient.HttpClient
return ShardManagerClientRpc.shardManagerClientRpc(
(shardManagerUri) =>
HttpRpcResolver.make<ShardingServiceRpc.ShardingServiceRpc>(
client.pipe(
HttpClient.filterStatusOk,
HttpClient.mapRequest(
HttpClientRequest.prependUrl(shardManagerUri)
)
)
).pipe(RpcResolver.toClient)
)
}))),
Layer.provide(ShardingConfig.withDefaults({ shardingPort: 54322 })),
Layer.provide(Serialization.json),
Layer.provide(NodeHttpClient.layerUndici)
Expand Down
31 changes: 21 additions & 10 deletions packages/cluster-node/examples/sample-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,14 @@ import * as StorageFile from "@effect/cluster-node/StorageFile"
import * as ManagerConfig from "@effect/cluster/ManagerConfig"
import * as PodsHealth from "@effect/cluster/PodsHealth"
import * as ShardManager from "@effect/cluster/ShardManager"
import { HttpClient, HttpClientRequest, HttpMiddleware, HttpRouter, HttpServer } from "@effect/platform"
import {
FetchHttpClient,
HttpClient,
HttpClientRequest,
HttpMiddleware,
HttpRouter,
HttpServer
} from "@effect/platform"
import { NodeHttpServer, NodeRuntime } from "@effect/platform-node"
import { RpcResolver } from "@effect/rpc"
import { HttpRpcResolver, HttpRpcRouter } from "@effect/rpc-http"
Expand Down Expand Up @@ -34,17 +41,21 @@ const liveShardingManager = Effect.never.pipe(
Layer.provide(ShardManager.live),
Layer.provide(StorageFile.storageFile),
Layer.provide(PodsHealth.local),
Layer.provide(PodsRpc.podsRpc<never>((podAddress) =>
HttpRpcResolver.make<ShardingServiceRpc.ShardingServiceRpc>(
HttpClient.fetchOk.pipe(
HttpClient.mapRequest(
HttpClientRequest.prependUrl(`http://${podAddress.host}:${podAddress.port}/api/rest`)
Layer.provide(Layer.unwrapEffect(Effect.gen(function*() {
const client = yield* HttpClient.HttpClient
return PodsRpc.podsRpc<never>((podAddress) =>
HttpRpcResolver.make<ShardingServiceRpc.ShardingServiceRpc>(
client.pipe(
HttpClient.filterStatusOk,
HttpClient.mapRequest(
HttpClientRequest.prependUrl(`http://${podAddress.host}:${podAddress.port}/api/rest`)
)
)
)
).pipe(RpcResolver.toClient)
)),
).pipe(RpcResolver.toClient)
)
}))),
Layer.provide(ManagerConfig.fromConfig),
Layer.provide(HttpClient.layer)
Layer.provide(FetchHttpClient.layer)
)

Layer.launch(liveShardingManager).pipe(
Expand Down
36 changes: 22 additions & 14 deletions packages/cluster-node/examples/sample-shard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,25 +62,33 @@ const liveLayer = Sharding.registerEntity(
Layer.provide(HttpLive),
Layer.provideMerge(Sharding.live),
Layer.provide(StorageFile.storageFile),
Layer.provide(PodsRpc.podsRpc<never>((podAddress) =>
HttpRpcResolver.make<ShardingServiceRpc.ShardingServiceRpc>(
HttpClient.fetchOk.pipe(
HttpClient.mapRequest(
HttpClientRequest.prependUrl(`http://${podAddress.host}:${podAddress.port}/api/rest`)
)
)
).pipe(RpcResolver.toClient)
)),
Layer.provide(ShardManagerClientRpc.shardManagerClientRpc(
(shardManagerUri) =>
Layer.provide(Layer.unwrapEffect(Effect.gen(function*() {
const client = yield* HttpClient.HttpClient
return PodsRpc.podsRpc<never>((podAddress) =>
HttpRpcResolver.make<ShardingServiceRpc.ShardingServiceRpc>(
HttpClient.fetchOk.pipe(
client.pipe(
HttpClient.filterStatusOk,
HttpClient.mapRequest(
HttpClientRequest.prependUrl(shardManagerUri)
HttpClientRequest.prependUrl(`http://${podAddress.host}:${podAddress.port}/api/rest`)
)
)
).pipe(RpcResolver.toClient)
)),
)
}))),
Layer.provide(Layer.unwrapEffect(Effect.gen(function*() {
const client = yield* HttpClient.HttpClient
return ShardManagerClientRpc.shardManagerClientRpc(
(shardManagerUri) =>
HttpRpcResolver.make<ShardingServiceRpc.ShardingServiceRpc>(
client.pipe(
HttpClient.filterStatusOk,
HttpClient.mapRequest(
HttpClientRequest.prependUrl(shardManagerUri)
)
)
).pipe(RpcResolver.toClient)
)
}))),
Layer.provide(Serialization.json),
Layer.provide(NodeHttpClient.layerUndici),
Layer.provide(ShardingConfig.fromConfig)
Expand Down
Loading