{"id":15331850,"url":"https://github.com/giusdp/funless","last_synced_at":"2025-10-10T02:31:16.187Z","repository":{"id":45402371,"uuid":"484791059","full_name":"giusdp/funless","owner":"giusdp","description":null,"archived":false,"fork":true,"pushed_at":"2025-09-23T14:06:55.000Z","size":1673,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-23T14:48:44.455Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Elixir","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"funlessdev/funless","license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/giusdp.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null}},"created_at":"2022-04-23T15:54:14.000Z","updated_at":"2025-03-05T16:36:40.000Z","dependencies_parsed_at":"2023-02-14T18:31:46.383Z","dependency_job_id":null,"html_url":"https://github.com/giusdp/funless","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/giusdp/funless","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giusdp%2Ffunless","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giusdp%2Ffunless/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giusdp%2Ffunless/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giusdp%2Ffunless/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/giusdp","download_url":"https://codeload.github.com/giusdp/funless/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giusdp%2Ffunless/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279002542,"owners_count":26083400,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-10T02:00:06.843Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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-10-01T09:56:54.733Z","updated_at":"2025-10-10T02:31:15.712Z","avatar_url":"https://github.com/giusdp.png","language":"Elixir","readme":"\u003c!--\n  ~ Copyright 2023 Giuseppe De Palma, Matteo Trentin\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~ http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n--\u003e\n\n\n[![documentation](https://img.shields.io/website?label=Documentation\u0026url=https%3A%2F%2Ffunless.dev)](https://funless.dev)\n![tests](https://github.com/funlessdev/funless/actions/workflows/core-ci.yml/badge.svg)\n[![release](https://badgen.net/github/release/funlessdev/funless)](https://github.com/funlessdev/funless/releases/)\n![contributors](https://badgen.net/github/contributors/funlessdev/funless) \n[![docker images](https://github.com/funlessdev/funless/actions/workflows/image-release.yml/badge.svg)](https://github.com/funlessdev/funless/packages)\n![Powered by WebAssembly](https://img.shields.io/badge/powered%20by-WebAssembly-orange.svg)\u003cbr /\u003e\n\n# FunLess\nThe Funless (FL) platform is a new generation, research-driven serverless platform built with with the scalability of the BEAM and the speed \nand security of WebAssembly. \n\nIt is a research project developed in the DISI department of the University of Bologna, with the aim to provide a new \nserverless platform for the Cloud-Edge computing paradigm.\n\nIt is still in an experimental state and not ready for production use yet, but it can be deployed either locally or \non a Kubernetes cluster and it is able to run user-defined functions. \n\n## Concepts\n\nThe main concepts behind the platform are:\n\n### Function\n\nA function is a unit of computation in the platform that can be created, deleted or invoked. \nIt is fundamentally a wasm binary that can be uploaded to the platform with a name, and with an associated module. It should be a wasm \nexecutable that takes as input a json object and returns a json object. We currently support building\nRust code to wasm via our [CLI tool](https://github.com/funlessdev/fl-cli).\n\n### Module\nA module is a collection of functions under the same name. It is used to group functions together to avoid name collisions.\nThe idea is the same behind the concept of module/namespace/package in other languages.\n\nEvery FunLess instance has a default module called `_`, which is used when creating/invoking/deleting a new function without specifying a particular module.\n\n### Events\n\nFunLess implements its own version of event connectors that can be used to trigger functions.\nWhen creating a new function, it is possible to \"connect\" it to an event source, which will trigger the function when a new event arrives.\n\nCurrently we only support an MQTT connector.\n\n### Data Sinks\n\nOn the other side of the event connectors, we have the data sinks.\nThey are used to send the output of a function to a specific destination.\nWhen creating a function, like for the events, it is possible to specify a data sink.\n\nCurrently we only support a CouchDB data sink, which stores all invocation results of the connected functions.\n\n### Web Assembly\n\nAt the basis of the platform there is WebAssembly. We are using the [wasmtime](https://wasmtime.dev/) runtime to execute wasm binaries.\nWeb Assembly is a relatively new technology that is gaining a lot of traction in the industry, and it is a perfect fit for serverless platforms.\nIt is a portable, sandboxed, and secure execution environment that can be used to run untrusted code. \n\nUsually serverless platforms use \neither containers or VMs to setup an execution environment suitable for a function (js code needs nodejs, rust needs its toolchain installed etc/), introducing overhead and cold-start times. With WebAssembly we are dealing with a ready to run binary, since the function code is compiled beforehand into an executable, therefore we can avoid containers setup and just run the code instead, resulting in near 0 cold-start time.\n\n## Architecture\n\n### Core\nAt the heart of the platform there is the **Core** component, which is the orchestrator of the platform. It manages functions and modules using a Postgres database behind. When an invocation request arrives, it acts as a scheduler to pick one of the available **Worker** componets, and it then sends the request to the worker to invoke the function (with the wasm binary if missing).\n\nThe core code resides in the apps/core folder, it is a Phoenix application that exposes a json REST API.\n\n### Worker\n\nThe Worker is the actual functions executor. It makes use of Rust NIFs to run user-defined functions via the wasmtime runtime.\nThe worker makes use of a cache to avoid requesting the same function multiple times, and it is able to run multiple functions in parallel.\nWhen the core sends an invocation request, the worker first tries to find the function in the cache, if it is not present it requests back to \nthe core the wasm binary. Then it executes the function and sends back the result to the core.\n\nThe worker code resides in the apps/worker folder.\n\n### Prometheus\n\nWe are using Prometheus to collect metrics from the platform. Besides collecting metrics from the Core and Worker, it is \nused by the Core to access the metrics of the Workers to make scheduling decisions.\n\n### Postgres\n\nWe are using Postgres as the platform database, used by the Core to store functions and modules.\n\n## CLI\n\nIt is recommended to use our [FunLess CLI](https://github.com/funlessdev/fl-cli) to interact with the platform, as it makes it easy to\ndo a local deployment and to deal with modules, functions and kickstart new function projects.\n\n## Developing FunLess\n\nYou need Elixir installed on your machine.\n\nWhen working on the platform, there are several ways to run it with your changes.\nOne is using the cli to do a local deployment with custom images. The local deployment uses `docker compose`, which runs\nthe docker images of the core and worker components, but it can be customized with the `--core` and `--worker` flags to use custom images.\nSo after making a change to the code, you can build the docker images and run the local deployment with the custom images.\n\nAnother way is to run the core and worker components directly, either the realeses or with `iex -S mix` for an interactive session.\nNote that this way you won't have prometheus running, so the core won't have access to metrics for scheduling.\n\n### Running with iex\n\nFirst of all you need to install the dependencies:\n\n```bash\nmix deps.get\n```\n\nThen you need to start the database, there is a docker-compose.yml file in the root of the project that can be used to start a postgres instance:\n\n```bash\ndocker compose up -d\n```\n\nNow to run the Core: \n\n```bash\ncd apps/core\nmix ecto.setup\niex --name core@127.0.0.1 --cookie default_secret -S mix phx.server\n```\n\nFor the Worker:\n\n```bash\ncd apps/worker \u0026\u0026 iex --name worker@127.0.0.1 --cookie default_secret -S mix\n```\n\nYou can check if the 2 components are seeing each other by writing in the Core iex terminal:\n\n```elixir\nNode.list()\n```\n\nIf it returns an empty list, connect them manually with:\n  \n```elixir\nNode.connect(:\"worker@127.0.0.1\")\n```\n\nNote: you might get spammed with prometheus error logs because there is no prometheus running, but you can ignore it.\n\nNow you can send requests to `localhost:4000`. The file `openapi/openapi.yaml` contains the OpenAPI specification of the API.\n\n### Mix Release\n\nThe project can also be compiled as a release, and run like this:\n\nFor the Core: \n```\nmix release core\n./_build/dev/rel/core/bin/core start (or daemon to run it in the background)\n```\n\nFor the Worker:\n```\nmix release worker\n./_build/dev/rel/worker/bin/worker start (or daemon to run it in the background)\n```\n\n### Run Tests\n\nThe tests are divided in unit tests and integration tests (which need a postgres instance running).\nFor the unit tests from the root folder:\n\n```bash\nmix core.test\nmix worker.test\n```\n\nFor the integration tests:\n  \n```bash\ncore.integration_test\n```\n\nOr you can enter the core/worker folder and run the tests from there.\n\n## Contributing\n\nAnyone is welcome to contribute to this project or any other FunLess project. \n\nYou can contribute by testing the projects, opening issues, writing documentation, sharing new ideas for future works and, of course,\nby contributing code. \n\nYou can pick an issue or create a new one, comment on it that you will take priority and then fork the repo so you're free to work on it.\nOnce you feel ready open a Pull Request to send your code to us.\n\n## License\n\nThis project is under the Apache 2.0 license.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgiusdp%2Ffunless","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgiusdp%2Ffunless","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgiusdp%2Ffunless/lists"}