How to send a web socket message from a cron lambda?

I’m following a couple of guides in sst website about cron jobs and web sockets.
How to create a WebSocket API with serverless (sst.dev)
How to use cron jobs in your serverless app (sst.dev)

Here’s how my cron lambda is trying to send a message to other clients connected to web sockets:

import { ApiGatewayManagementApi } from "@aws-sdk/client-apigatewaymanagementapi";
import { WebSocketApi } from "sst/node/api";
import { Table } from "sst/node/table";
import { dynamodb } from "../../core/src/functions/dynamodb";

export const handler = async () => {
  const webSocketApi = new ApiGatewayManagementApi({
    endpoint: WebSocketApi.WebStocketApi.url,
  });

  console.log("Web socket API URL", WebSocketApi.WebStocketApi.url);
  console.log("Web socket API", webSocketApi);

  const connections = await dynamodb.scan({
    TableName: Table.WebSocketConnections.tableName,
    ProjectionExpression: "id",
  });

  if (!connections.Items?.length) {
    return {};
  }

  const message = {
    numberOfConnections: connections.Items,
  };

  connections.Items?.forEach((c) => {
    webSocketApi.postToConnection({
      ConnectionId: c.id,
      Data: Uint8Array.from(
        JSON.stringify(message)
          .split("")
          .map((c) => c.charCodeAt(0))
      ),
    });
  });
  return {};
};

As you can see in the console logs, the web socket API URL is fully qualified and is correct (can connect via postman web socket connection):

| Invoked packages/functions/src/sendNumberOfConnections.handler
| +945ms Web socket API URL wss://vhq358ir91.execute-api.eu-west-2.amazonaws.com/FabioMilheiro

However, I’m getting this error:

Error: getaddrinfo ENOTFOUND execute-api.eu-west-2.amazonaws.com

Trace: Error: getaddrinfo ENOTFOUND execute-api.eu-west-2.amazonaws.com
at __node_internal_captureLargerStackTrace (node:internal/errors:464:5)
at _node_internal (node:internal/errors:686:10)
at GetAddrInfoReqWrap.onlookup [as oncomplete] (node:dns:71:26)
at GetAddrInfoReqWrap.callbackTrampoline (node:internal/async_hooks:130:17)
at process. (file:///C:/dev/xp/sst-links/node_modules/sst/cli/sst.js:58:17)
at process.emit (node:events:532:35)
at processEmit [as emit] (C:\dev\xp\sst-links\node_modules\signal-exit\index.js:199:34)
at process._fatalException (node:internal/process/execution:164:25)

at 0x7FF725DE6E60: uv_poll_stop
at 0x7FF726BDC5E0: v8::internal::compiler::RepresentationChanger::Uint32OverflowOperatorFor
at 0x7FFB6A7D5590: BaseThreadInitThunk
at 0x7FFB6B804830: RtlUserThreadStart
PS C:\dev\xp\sst-links>

Above you can read that It mentions that the address is not found and refers to only a part of it.

Is the problem really the URL or am I doing something else wrong?

If anyone ends up interested, my solution is below.

I needed to do a few things. I have access to the websocket api address prefixed with wss:// but needed https:// so I just replaced.

The other issue I had to solve was to bind the cron to the websocket api and attach “execute-api” permissions:

  cron.bind([connectionsTable, webSocketApi]);
  cron.attachPermissions(["execute-api"]);
import { ApiGatewayManagementApi } from "@aws-sdk/client-apigatewaymanagementapi";
import { WebSocketApi } from "sst/node/api";
import { Table } from "sst/node/table";
import { dynamodb } from "../../core/src/functions/dynamodb";

export const handler = async () => {
  const webSocketApi = new ApiGatewayManagementApi({
    endpoint: WebSocketApi.WebStocketApi.url.replace("wss://", "https://"),
  });

  const connections = await dynamodb.scan({
    TableName: Table.WebSocketConnections.tableName,
    ProjectionExpression: "id",
  });

  if (!connections.Items?.length) {
    return {};
  }

  const message = {
    numberOfConnections: connections.Items?.length ?? 0,
  };

  connections.Items?.forEach(async (c) => {
    console.log("Sending message to connection id", c.id);
    webSocketApi
      .postToConnection({
        ConnectionId: c.id,
        Data: Uint8Array.from(
          JSON.stringify(message)
            .split("")
            .map((c) => c.charCodeAt(0))
        ),
      })
      .catch(async (err) => {
        console.error("Could not send message", err);
        await dynamodb.delete({
          TableName: Table.WebSocketConnections.tableName,
          Key: {
            id: c.id,
          },
        });
        console.error(`Deleted stale connection ${c.id}`);
      });
  });
  return {};
};

Hope it helps others!