{"id":19865656,"url":"https://github.com/openfaas/classic-watchdog","last_synced_at":"2026-02-05T09:09:41.449Z","repository":{"id":40465043,"uuid":"309349438","full_name":"openfaas/classic-watchdog","owner":"openfaas","description":"Classic Watchdog for OpenFaaS","archived":false,"fork":false,"pushed_at":"2025-05-16T11:14:46.000Z","size":4166,"stargazers_count":29,"open_issues_count":1,"forks_count":16,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-05-24T10:06:04.938Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/openfaas.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-11-02T11:27:35.000Z","updated_at":"2025-05-16T11:14:49.000Z","dependencies_parsed_at":"2025-02-24T05:00:41.768Z","dependency_job_id":"95049d81-7f66-4007-877b-6efc5a1bcaac","html_url":"https://github.com/openfaas/classic-watchdog","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/openfaas/classic-watchdog","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openfaas%2Fclassic-watchdog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openfaas%2Fclassic-watchdog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openfaas%2Fclassic-watchdog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openfaas%2Fclassic-watchdog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/openfaas","download_url":"https://codeload.github.com/openfaas/classic-watchdog/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openfaas%2Fclassic-watchdog/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29117917,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-05T05:31:32.482Z","status":"ssl_error","status_checked_at":"2026-02-05T05:31:29.075Z","response_time":65,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-12T15:23:37.644Z","updated_at":"2026-02-05T09:09:41.422Z","avatar_url":"https://github.com/openfaas.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"Watchdog\n==========\n\nThe watchdog provides an interface between the outside world and your function. It starts a new process for each request and uses STDIO for communication.\n\n![Classic watchdog architecture](https://pbs.twimg.com/media/DGScDblUIAAo4H-.jpg:large)\n\n\u003e  Above: a tiny web-server or shim that forks your desired process for every incoming HTTP request\n\nEvery function needs to embed this binary and use it as its `ENTRYPOINT` or `CMD`, in effect it is the init process for your container. Once your process is forked the watchdog passses in the HTTP request via `stdin` and reads a HTTP response via `stdout`. This means your process does not need to know anything about the web or HTTP.\n\n### Next-gen: of-watchdog\n\nAre you looking for more control over your HTTP responses, \"hot functions\", persistent connection pools or to cache a machine-learning model in memory? Then check out the *http mode* of the new [of-watchdog](https://github.com/openfaas-incubator/of-watchdog).\n\n## Create a new function the easy way\n\n**Create a function via the CLI**\n\nThe easiest way to create a function is to use a template and the FaaS CLI. The CLI allows you to abstract all Docker knowledge away, you just have to write a handler file in one of the supported programming languages.\n\n* [Your first serverless Python function with OpenFaaS](https://blog.alexellis.io/first-faas-python-function/)\n\n* [Read a tutorial on the FaaS CLI](https://github.com/openfaas/faas-cli)\n\n## Delve deeper\n\n**Package your function**\n\nHere's how to package your function if you don't want to use the CLI or have existing binaries or images:\n\n- [x] Use an existing or a new Docker image as base image `FROM`\n- [x] Add the fwatchdog binary from the [Releases page](https://github.com/openfaas/faas/releases) via `curl` or `ADD https://`\n- [x] Set an `fprocess` (function process) environmental variable with the function you want to run for each request\n- [x] Expose port 8080\n- [x] Set the `CMD` to `fwatchdog`\n\nExample Dockerfile for an `echo` function:\n\n```\nFROM alpine:3.13\n\nADD https://github.com/openfaas/faas/releases/download/0.18.10/fwatchdog /usr/bin\nRUN chmod +x /usr/bin/fwatchdog\n\n# Define your binary here\nENV fprocess=\"/bin/cat\"\n\nCMD [\"fwatchdog\"]\n```\n\n**Tip:**\nYou can optimize Docker to cache getting the watchdog by using curl, instead of ADD.\nTo do so, replace the related lines with:\n```\nRUN apk --no-cache add curl \\\n    \u0026\u0026 curl -sL https://github.com/openfaas/faas/releases/download/0.9.14/fwatchdog \u003e /usr/bin/fwatchdog \\\n    \u0026\u0026 chmod +x /usr/bin/fwatchdog\n```\n\n**Implementing a health-check**\n\nAt any point in time, if you detect that your function has become unhealthy and needs to restart, then you can delete the `/tmp/.lock` file which invalidates the check and causes Swarm to re-schedule the function.\n\n* Kubernetes\n\nFor Kubernetes the health check is added through automation without you needing to alter the `Dockerfile`.\n\n* Swarm\n\nA Docker Swarm Healthcheck is required and is best practice. It will make sure that the watchdog is ready to accept a request before forwarding requests via the API Gateway. If the function or watchdog runs into an unrecoverable issue Swarm will also be able to restart the container.\n\nHere is an example of the `echo` function implementing a *health check* with a 5-second checking interval.\n\n```\nFROM functions/alpine\n\nENV fprocess=\"cat /etc/hostname\"\n\nHEALTHCHECK --interval=5s CMD [ -e /tmp/.lock ] || exit 1\n```\n\nThe watchdog process creates a .lock file in `/tmp/` on starting its internal Golang HTTP server. `[ -e file_name ]` is shell to check if a file exists. With Windows Containers this is an invalid path so you may want to set the `suppress_lock` environmental variable.\n\nRead my Docker Swarm tutorial on Healthchecks:\n\n * [Test-drive Docker Healthcheck in 10 minutes](http://blog.alexellis.io/test-drive-healthcheck/)\n\n## Environment variable overrides:\n\nThe watchdog can be configured through environment variables. You must always specifiy an `fprocess` variable.\n\n| Option                 | Usage             |\n|------------------------|--------------|\n| `fprocess`             | The process to invoke for each function call (function process). This must be a UNIX binary and accept input via STDIN and output via STDOUT  |\n| `cgi_headers`          | HTTP headers from request are made available through environmental variables - `Http_X_Served_By` etc. See section: *Handling headers* for more detail. Enabled by default |\n| `marshal_request`     | Instead of re-directing the raw HTTP body into your fprocess, it will first be marshalled into JSON. Use this if you need to work with HTTP headers and do not want to use environmental variables via the `cgi_headers` flag. |\n| `content_type`         | Force a specific Content-Type response for all responses |\n| `write_timeout`        | HTTP timeout for writing a response body from your function (in seconds)  |\n| `read_timeout`         | HTTP timeout for reading the payload from the client caller (in seconds) |\n| `healthcheck_interval` | Interval (in seconds) for HTTP healthcheck by container orchestrator i.e. kubelet. Used for graceful shutdowns. |\n| `suppress_lock`        | The watchdog will attempt to write a lockfile to /tmp/ for swarm healthchecks - set this to true to disable behaviour. |\n| `exec_timeout`         | Hard timeout for process exec'd for each incoming request (in seconds). Disabled if set to 0 |\n| `write_debug`          | Write all output, error messages, and additional information to the logs. Default is false |\n| `combine_output`       | True by default - combines stdout/stderr in function response, when set to false `stderr` is written to the container logs and stdout is used for function response |\n| `max_inflight`         | Limit the maximum number of requests in flight |\n| `jwt_auth`                       | For OpenFaaS for Enterprises customers only. When set to `true`, the watchdog will require a JWT token to be passed as a Bearer token in the Authorization header. This token can only be obtained through the OpenFaaS gateway using a token exchange using the `http://gateway.openfaas:8080` address as the authority. |\n| `jwt_auth_debug`                 | Print out debug messages from the JWT authentication process (OpenFaaS for Enterprises only). |\n| `jwt_auth_local`                 | When set to `true`, the watchdog will attempt to validate the JWT token using a port-forwarded or local gateway running at `http://127.0.0.1:8080` instead of attempting to reach it via an in-cluster service name  (OpenFaaS for Enterprises only). |\n\n## Metrics\n\n| Name                            | Description             | Type                   |\n|---------------------------------|-------------------------|------------------------|\n| http_requests_total             | Total number of requests | Counter               |\n| http_request_duration_seconds   | Duration of requests    | Histogram              |\n| http_requests_in_flight         | Number of requests in-flight | Gauge             |\n\n## Advanced / tuning\n\n### (New) of-watchdog and HTTP mode\n\n* of-watchdog\n\nForking a new process per request has advantages such as process isolation, portability and simplicity. Any process can be made into a function without any additional code. The of-watchdog and its \"HTTP\" mode is an optimization which maintains one single process between all requests.\n\nA new version of the watchdog is being tested over at [openfaas-incubator/of-watchdog](https://github.com/openfaas-incubator/of-watchdog).\n\nThis re-write is mainly structural for on-going maintenance. It will be a drop-in replacement for the existing watchdog and also has binary releases available.\n\n### Graceful shutdowns\n\nThe watchdog is capable of working with health-checks to provide a graceful shutdown.\n\nWhen a `SIGTERM` signal is detected within the watchdog process a Go routine will remove the `/tmp/.lock` file and mark the HTTP health-check as unhealthy and return HTTP 503. The code will then wait for the duration specified in `write_timeout`. During this window the container-orchestrator's health-check must run and complete.\n\nNow the orchestrator will mark this replica as unhealthy and remove it from the pool of valid HTTP endpoints.\n\nNow we will stop accepting new connections and wait for the value defined in `write_timeout` before finally allowing the process to exit.\n\n### Working with HTTP headers\n\nHeaders and other request information are injected into environmental variables in the following format:\n\nThe `X-Forwarded-By` header becomes available as `Http_X_Forwarded_By`\n\n* `Http_Method` - GET/POST etc\n* `Http_Query` - QueryString value\n* `Http_ContentLength` and `Http_Content_Length` - gives the total content-length of the incoming HTTP request received by the watchdog, see note below\n* `Http_Transfer_Encoding` - only set when provided, if set to `chunked` the Content-Length will be `-1` to show that it does not apply\n\n\u003e This behaviour is enabled by the `cgi_headers` environmental variable which is enabled (`true`) by default.\n\nHere's an example of a POST request with an additional header and a query-string.\n\n```\n$ cgi_headers=true fprocess=env ./watchdog \u0026\n2017/06/23 17:02:58 Writing lock-file to: /tmp/.lock\n\n$ curl \"localhost:8080?q=serverless\u0026page=1\" -X POST -H X-Forwarded-By:http://my.vpn.com\n```\n\nThis is what you'd see if you had set your `fprocess` to `env` on a Linux system:\n\n```\nHttp_User_Agent=curl/7.43.0\nHttp_Accept=*/*\nHttp_X_Forwarded_By=http://my.vpn.com\nHttp_Method=POST\nHttp_Query=q=serverless\u0026page=1\n```\n\nYou can also use the `GET` verb:\n\n```\n$ curl \"localhost:8080?action=quote\u0026qty=1\u0026productId=105\"\n```\n\nThe output from the watchdog would be:\n\n```\nHttp_User_Agent=curl/7.43.0\nHttp_Accept=*/*\nHttp_Method=GET\nHttp_Query=action=quote\u0026qty=1\u0026productId=105\n```\n\nYou can now use HTTP state from within your application to make decisions.\n\n### HTTP methods\n\nThe HTTP methods supported for the watchdog are:\n\nWith a body:\n* POST, PUT, DELETE, UPDATE\n\nWithout a body:\n* GET\n\n\u003e The API Gateway currently supports the POST route for functions.\n\n### Content-Type of request/response\n\nBy default the watchdog will match the response of your function to the \"Content-Type\" of the client.\n\n* If your client sends a JSON post with a Content-Type of `application/json` this will be matched automatically in the response.\n* If your client sends a JSON post with a Content-Type of `text/plain` this will be matched automatically in the response too\n\nTo override the Content-Type of all your responses set the `content_type` environmental variable.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenfaas%2Fclassic-watchdog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopenfaas%2Fclassic-watchdog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenfaas%2Fclassic-watchdog/lists"}