Skip to content

The socket.runRaw from NodeSocketServer.layerWebSocket prevents Effect.fn usage #4852

@loklaan

Description

@loklaan

What version of Effect is running?

3.14.18

What steps can reproduce the bug?

Versions

@effect/platform: ^0.80.18
@effect/platform-node: ^0.77.6
effect: ^3.14.18

Full Reproduction

// socket-runraw--effect-fn.reproduction.ts
import { SocketServer } from '@effect/platform';
import { NodeContext, NodeRuntime, NodeSocketServer } from '@effect/platform-node';
import { Effect } from 'effect';

const PORT = 3001;

const runWebSocketServer = Effect.gen(function* () {
  const server = yield* SocketServer.SocketServer;

  let id = 0;
  yield* Effect.log(`Listening on port ${PORT}`)
  yield* server.run((socket) => {
    const clientId = ++id;

    return Effect.gen(function* () {
      yield* Effect.log(`Client connected`);
      const clientWriter = yield* socket.writer;

      // Use of Effect.fn here is causing the "RuntimeException: Not a valid effect: {}" error.
      // Note that (msg) => Effect.gen(...).pipe(Effect.withSpan('handle socket message')) works fine, as a workaround.
      yield* socket.runRaw(Effect.fn('handle socket message')(function* (msg) {
        yield* Effect.log('Client message received:', msg);
        const responseMsg = `Ping-pong: ${msg}`;
        yield* Effect.log("Ponging back:", responseMsg);
        yield* clientWriter(responseMsg);

      // Note:
      // The fiber for the socket message isn't forked from the server's fiber, so context/fiberrefs/handlers must be setup again :(
      })).pipe(Effect.catchAllCause(Effect.logError));
    }).pipe(Effect.annotateLogs({ clientId }));
  });

  return yield* Effect.never;
});

NodeRuntime.runMain(
  runWebSocketServer.pipe(
    Effect.catchAllCause(Effect.logError),
    Effect.scoped,
    Effect.provide(NodeContext.layer),
    Effect.provide(NodeSocketServer.layerWebSocket({ port: PORT })),
    Effect.catchAllCause(Effect.logError),
    Effect.orDie
  )
);

What is the expected behavior?

The equivilent below is working fine, as a workaround:

socket.run(msg => Effect.gen(function* () {
   // ...
}).pipe(Effect.withSpan('label')))

What do you see instead?

The following snippet from the repro cannot run, and is produceding "RuntimeException: Not a valid effect: {}" errors.

socket.run(Effect.fn('label')(function* (msg) {
   // ...
}))

Additional information

Also, and this might warrant a different Issue, the fiber refs and context aren't inheritted by the fiber that is handling the message, so things like set log level / layers aren't propogating down... Is that intentional?

I found that manually passing down Effect.inheritFiberRefs(serverFiberRefs) / Effect.provide(serverContext) inside the message handler generator remedies this, but it's cumbersome.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions