Skip to content
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
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,18 @@ through the API - is served over HTTP at its `standbyUrl`, on the API port:
```bash
cd sample_actor_standby_ts # or sample_actor_standby_py
apify push
curl "http://localhost:3333/actor-runtime/standby/<username>--my-standby-actor-ts/hello?name=Ada&token=<token>"
curl "http://<username>--my-standby-actor-ts.localhost:3333/hello?name=Ada&token=<token>"
```

The `standbyUrl` has the platform's shape, one `*.localhost` hostname per Actor, so a web UI served by the
Actor works as on `*.apify.actor`. Clients that do not resolve `*.localhost` use
`http://localhost:3333/actor-runtime/standby/<username>--<actor-name>`, and other Actors
`http://apify-api:3333/actor-runtime/standby/<username>--<actor-name>`.

The two samples are the same server in TypeScript and Python - JSON endpoints, a request body echo, a
Server-Sent Events stream, a websocket and stats kept across runs; each README lists the calls.
`sample_actor_standby_web` serves a web page with root-relative links, and in an ordinary run calls a
standby Actor from inside its container.

Requests are handed to standby runs the runtime starts, scales by `desiredRequestsPerActorRun` /
`maxRequestsPerActorRun` and winds down after `idleTimeoutSecs` without a request, as on the platform.
Expand Down
12 changes: 7 additions & 5 deletions requirements/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,13 @@
`null` while Standby is off. `POST` and `PUT /v2/actors` accept `actorStandby`; a partial object is merged
over the stored settings, over the defaults. An invalid one is `400` `invalid-request`, changing nothing;
a `tenancy` other than `SINGLE_TENANT` is invalid.
- The standby URL is `http://localhost:3333/actor-runtime/standby/<username>--<actor-name>`; the Actor id
also works in place of `<username>--<actor-name>`. Everything after it - path, query, method, headers,
body, websocket upgrades - reaches the Actor's server unchanged, the token included.
- The platform's host-based shape, `http://<username>--<actor-name>.localhost:3333/<path>`, is served too,
for clients that resolve `*.localhost`; its whole path reaches the Actor.
- The standby URL is `http://<username>--<actor-name>.localhost:3333`, the local `*.apify.actor`: each
Actor has its own origin and owns its whole path, so web UIs served by Actors work as on the platform.
- Clients that do not resolve `*.localhost` use `http://localhost:3333/actor-runtime/standby/<username>--<actor-name>`;
other Actors use `http://apify-api:3333/actor-runtime/standby/<username>--<actor-name>`, which is the
`standbyUrl` they read through the API.
- The Actor id can replace `<username>--<actor-name>`. Path, query, method, headers, body and websockets
reach the Actor's server unchanged.
- Authenticated like the API (`Authorization: Bearer`, `?token=`), plus the platform's
`x-apify-authorization` header; only the Actor's owner is served.
- Errors, as `{ "error": { "type", "message" } }`: no token `401` `user-not-authenticated`; no such Actor of
Expand Down
2 changes: 2 additions & 0 deletions requirements/test.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,5 @@ Test case must verify full Actor development flow:
- Assert that plain, body-carrying, streamed and websocket requests to its standby URL are all answered by
one `STANDBY` run, that the run ends `SUCCEEDED` once idle with one dataset item per greeting, and that
the next request starts a new run
- For `sample_actor_standby_web`: assert that an external client and another Actor's run can both call its
standby endpoint
12 changes: 12 additions & 0 deletions sample_actor_standby_web/.actor/actor.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"$schema": "https://apify.com/schemas/v1/actor.ide.json",
"actorSpecification": 1,
"name": "my-standby-web-actor",
"title": "Standby web page sample actor for actor-runtime",
"description": "In Standby mode, a web page and the JSON endpoint it calls with a root-relative URL. An ordinary run calls a standby Actor's endpoint from inside its container.",
"version": "0.0",
"buildTag": "latest",
"usesStandbyMode": true,
"input": "./input_schema.json",
"dockerfile": "../Dockerfile"
}
20 changes: 20 additions & 0 deletions sample_actor_standby_web/.actor/input_schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"title": "Standby web sample input",
"type": "object",
"schemaVersion": 1,
"properties": {
"standbyActor": {
"title": "Standby Actor",
"type": "string",
"description": "The standby Actor an ordinary run calls, as an id or `username/name`. Empty means this Actor itself.",
"editor": "textfield"
},
"name": {
"title": "Name",
"type": "string",
"description": "Sent to the standby Actor's `/api/greeting` endpoint.",
"editor": "textfield",
"default": "Actor"
}
}
}
18 changes: 18 additions & 0 deletions sample_actor_standby_web/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# configurations
.idea
.vscode
.zed

# crawlee and apify storage folders
apify_storage
crawlee_storage
storage

# installed files
node_modules

# git folder
.git

# dist folder
dist
20 changes: 20 additions & 0 deletions sample_actor_standby_web/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
FROM apify/actor-node:24 AS builder

COPY --chown=myuser:myuser package*.json ./
RUN npm install --include=dev --audit=false

COPY --chown=myuser:myuser . ./
RUN npm run build

FROM apify/actor-node:24

COPY --chown=myuser:myuser package*.json ./
RUN npm --quiet set progress=false \
&& npm install --omit=dev --omit=optional --audit=false \
&& rm -r ~/.npm

COPY --from=builder --chown=myuser:myuser /usr/src/app/dist ./dist
COPY --chown=myuser:myuser . ./

# The interpreter itself, not `npm start`, so the runtime's debug mode can attach too.
CMD ["node", "dist/main.js"]
24 changes: 24 additions & 0 deletions sample_actor_standby_web/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Standby web sample Actor

A small Actor for trying Actor Standby callers against the local runtime. `.actor/actor.json` sets
`usesStandbyMode`, so `apify push` enables Standby.

- **Standby run**: serves a web page whose script calls `GET /api/greeting` with a root-relative URL, as most
web UIs do. That works because the Actor owns `/` of its standby URL, as on `*.apify.actor`.
- **Ordinary run** (`apify call`): a client of a standby Actor, this one unless the `standbyActor` input
names another. It reads that Actor's `standbyUrl` through the API - from inside a container that is
`http://apify-api:3333/actor-runtime/standby/<username>--<actor-name>` - calls `/api/greeting` there and
pushes the answer to its default dataset.

```bash
apify push
TOKEN=<your token>

# In a browser:
# http://<username>--my-standby-web-actor.localhost:3333/?token=<your token>
curl "http://<username>--my-standby-web-actor.localhost:3333/api/greeting?name=Ada&token=$TOKEN"
# The same endpoint, for clients that do not resolve *.localhost:
curl "http://localhost:3333/actor-runtime/standby/<username>--my-standby-web-actor/api/greeting?name=Ada&token=$TOKEN"

apify call --input '{"name":"Actor"}' # another run calls the standby endpoint from its container
```
Loading
Loading