{"id":19811040,"url":"https://github.com/accenture/mercury-python","last_synced_at":"2025-05-01T08:32:24.654Z","repository":{"id":35400900,"uuid":"179631607","full_name":"Accenture/mercury-python","owner":"Accenture","description":"Python language pack for Mercury","archived":false,"fork":false,"pushed_at":"2024-12-16T20:50:53.000Z","size":240,"stargazers_count":11,"open_issues_count":0,"forks_count":6,"subscribers_count":10,"default_branch":"main","last_synced_at":"2025-04-06T11:51:43.404Z","etag":null,"topics":["anonymous-functions","event-driven","event-stream","language-connector","mercury-framework","microservices","reactive"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Accenture.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","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}},"created_at":"2019-04-05T06:42:37.000Z","updated_at":"2025-01-16T01:30:53.000Z","dependencies_parsed_at":"2024-05-09T16:41:31.536Z","dependency_job_id":null,"html_url":"https://github.com/Accenture/mercury-python","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Accenture%2Fmercury-python","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Accenture%2Fmercury-python/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Accenture%2Fmercury-python/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Accenture%2Fmercury-python/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Accenture","download_url":"https://codeload.github.com/Accenture/mercury-python/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251847828,"owners_count":21653582,"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","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":["anonymous-functions","event-driven","event-stream","language-connector","mercury-framework","microservices","reactive"],"created_at":"2024-11-12T09:24:32.413Z","updated_at":"2025-05-01T08:32:24.344Z","avatar_url":"https://github.com/Accenture.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# This project is pending upgrade to Mercury 3.0\n\nPlease note that this project is pending refactoring to catch up with Composable design patterns in Mercury 3.1.\n\nWe will archive this to a branch and document the migration steps when it happens.\n\n# Python language pack for the Mercury microservices framework\n\nYou can write standalone or cloud application using this software development tool.\n\nWhen running as a distributed application, this module requires the Mercury Language Connector application as a sidecar.\nThe main Mercury project is available at https://github.com/Accenture/mercury\n\nPlease clone the main project and follow the README file to build the mercury core libraries and the language-connector application.\n\n## Installing mercury\n\nYou may install mercury using pip as follows:\n```\npip install git+https://github.com/Accenture/mercury-python.git\n```\n\n## Welcome to the Mercury project\n\nThe Mercury project is created with one primary objective - `to make software easy to write, read, test, deploy, scale and manage`.\n\nIt introduces the concept of platform abstraction and takes event driven programming to the next level of simplicity and sophistication.\n\nEverything can be expressed as anonymous functions and they communicate with each other using events. This includes turning synchronous HTTP requests and responses into async events using the REST automation system. However, event driven and reactive programming can be challenging. The Mercury framework hides all the complexity of event driven and reactive patterns and the magic of inter-service communication.\n\nIf you want digital decoupling, this is the technology that you should invest 30 minutes of your time to get familiar with.\n\nThe pre-requisites are minimal. The foundation technology requires only Java (OpenJDK 8 to 14) and the Maven build system (\"mvn\"). Docker/Kubernetes are optional. The application modules that you create using the Mercury framework will run in bare metal, VM and any cloud environments.\n\nThis project is created by architects and computer scientists who have spent years to perfect software decoupling, scalability and resilience, high performance and massively parallel processing,\n\nWith a very high level of decoupling, you can focus in writing business logic without distraction.\n\nSince everything can be expressed as anonymous functions, the framework itself is written using this approach, including the cloud connectors and language pack in the project. In this way, you can add new connectors, plugins and language packs as you like. The framework is extensible.\n\nThe concept is simple. You write your business logic as anonymous functions and packaged them in one or more executables. These executables may be composed as Docker images or alike for deployment. The services in the containers communicate with each other using \"service route names\".\n\nMercury supports unlimited service route names on top of event stream and messaging systems such as Kafka and Hazelcast. While we make the event stream system works as a service mesh, Mercury can be used in standalone mode for applications that use pub/sub directly.\n\nIn fact, you can encapsulate other event stream or even enterprise service bus (ESB) with Mercury. Just use the Kafka and Hazelcast connectors as examples. It would make your ESB runs like an event stream system for RPC, async, callback, streaming, pipeline and pub/sub use cases.\n\nBest regards, the Mercury team, Accenture\n\nMay 2022\n\n## Rationale\n\nThe microservices movement is gaining a lot of momentum in recent years. Very much inspired with the need to modernize service-oriented architecture and to transform monolithic applications as manageable and reusable pieces, it was first mentioned in 2011 to advocate an architectural style that defines an application as a set of loosely coupled single purpose services.\n\nClassical model of microservices architecture often focuses in the use of REST as interface and the self-containment of data and process. Oftentimes, there is a need for inter-service communication because one service may consume another service. Usually this is done with a service broker. This is an elegant architectural concept. However, many production systems face operational challenges. In reality, it is quite difficult to decompose a solution down to functional level. This applies to both green field development or application modernization. As a result, many microservices modules are indeed smaller subsystems. Within a microservice, business logic is tightly coupled with 3rd party and open sources libraries including cloud platform client components and drivers. This is suboptimal.\n\n## Architecture principles\n\nFor simplicity, we advocate 3 architecture principles to write microservices\n\n- minimalist\n- event driven\n- context bound\n\nMinimalist means we want user software to be as small as possible. The Mercury framework allows you to write business logic down to functional level using simple input-process-output pattern.\n\nEvent driven promotes loose coupling. All functions should run concurrently and independently of each other.\n\nLastly, context bound means high level of encapsulation so that a function only expose API contract and nothing else.\n\n### Platform abstraction\n\nMercury offers the highest level of decoupling where each piece of business logic can be expressed as an anonymous function. A microservices module is a collection of one or more functions. These functions connect to each other using events.\n\nThe framework hides the complexity of event-driven programming and cloud platform integration. For the latter, the service mesh interface is fully encapsulated so that user functions do not need to be aware of network connectivity and details of the cloud platform.\n\n### Simple Input-Process-Output function\n\nThis is a best practice in software development. Input is fed into an anonymous function. It will process the input according to some API contract and produce some output.\n\nThis simplifies software development and unit tests.\n\n\n## Defining a microservice\n\nAn application can declare one or more Python functions as microservices.\nYour microservices function or method must use one of the following signatures:\n\n```\n# For singleton service\nf(headers: dict, body: any)\n\n# For service that have concurrent workers\nf(headers: dict, body: any, instance: int)\n\n# For interceptor service - this allows your application to inspect event metdata\nf(event: EventEnvelope)\n\n# f can be any function or method name you like\n# headers are input parameters in key-value pairs\n# body is application specific. It can be string, byte array, dictionary, etc.\n# instance is the instance number when the lambda function is registered to support multiple instances\n# event is the event envelope that contains routing metadata, input parameters and message body\n#\n# headers, body, instance and envelope are standard parameter names that your functions should use.\n```\n\nYou may then register your microservices like this:\n\n`platform.register(route: str, user_function: any, total_instances: int, is_private: bool = False)`\n\n```python\nfrom mercury.platform import Platform\n\ndef hello(headers: dict, body: any, instance: int):\n    # business logic here\n    return result\n\n#\n# Once you have defined a microservice, you should register it with a route name.\n# The route name for your anonymous function is like the home address of a house so it can receive letters.\n#\nplatform = Platform()\nplatform.register(\"hello.world\", hello, 10)\n```\n\nTo make the service available to other nodes in the system, you can connect your application to the cloud.\n\n```\nplatform.connect_to_cloud()\n```\n\n## making a RPC call\n\nYou may make a RPC service call like this. Note that everything is non-blocking in the Mercury framework.\n\nRPC uses a temporary inbox service to simulate a synchronous request-response.\n\n```python\nfrom mercury.platform import Platform\nfrom mercury.system.po import PostOffice\n\n#\n# The signature of the request method is:\n#    request(self, route: str, timeout_seconds: float,\n#            headers: dict = None, body: any = None,\n#            correlation_id: str = None) -\u003e EventEnvelope\n#\n\npo = PostOffice()\ntry:\n    result = po.request('hello.world', 2.0, headers={'some_key': 'some_value'}, body='test message')\n    if isinstance(result, EventEnvelope):\n        print('Received RPC response:')\n        print(\"HEADERS =\", result.get_headers(), \", BODY =\", result.get_body(),\n              \", STATUS =\", result.get_status(),\n              \", EXEC =\", result.get_exec_time(), \", ROUND TRIP =\", result.get_round_trip(), \"ms\")\nexcept TimeoutError as e:\n    print(\"Exception: \", str(e))\n```\n\n## making an asynchronous call\n\nYou can make a \"drop-n-forget\" asynchronous request to a service like this:\n\n```python\n#\n# The signature of the send method is:\n# send(self, route: str, headers: dict = None, body: any = None, reply_to: str = None, me=True) -\u003e None\n#\n\npo.send('hello.world', headers={'one': 1}, body='hello world one')\n\n```\n\n## call back\n\nYou can set the route of a call back function in the \"reply to\" of the request in the send() method. \nWhen the service responds, the result will be delivered asynchronously to the call back function.\n\nThe default value for the \"me\" parameter is true. It guarantees that the response will be returned to your calling application.\n\nIf you want the system to send the response to any function with the same route name, set the \"me\" parameter to false.\n\n## stopping the platform event loop\n\nThe platform kernel is running in an event loop using Python asyncio. \nYou may want to call the following when your application quits.\nThis will ask the system to release resources and stop gracefully.\n\n```\nplatform.stop()\n```\n\n## stopping the application using Control-C\n\nYou may enable Control-C and Kill signal detection by calling the \"run_forever()\" method. Note that this must be done with the main thread.\n\n```\nplatform.run_forever()\n```\n\n## Pre-requisites\n\nPlease do `pip install wheel` if python wheel is not installed.\n\nMercury requires python 3.6.7 or above.\n\n## Typical installation issue\n\nYou may install mercury using pip as follows:\n```\npip install git+https://github.com/Accenture/mercury-python.git\n```\n\nYou should always use `pip` to install. If you accidentally installed mercury using \"python setup.py install\", \nyou will see the following error when trying to upgrade or uninstall.\n```\nCannot uninstall 'mercury'. \nIt is a distutils installed project and thus we cannot accurately determine\nwhich files belong to it which would lead to only a partial uninstall.\n```\nYou can resolve this issue by reinstalling mercury with the option \"--ignore-installed\". \nThis will restore the metadata information for pip.\n```\npip install --ignore-installed git+https://github.com/Accenture/mercury-python.git\n```\n\n## Application configuration file\n\nThe default application config file is located in resources/application.yml.\n\nTo use your own config file, please specify \"config_file=your_config_file_path\" when creating the platform instance.\nPlease use application.yml as a template and update the parameters.\ne.g.\n```\nplatform = Platform(config_file='/tmp/config/application.yml')\n```\n\n## language connector's shared secret key\n\nlanguage.pack.key should point to an environment variable containing a secret key for connection to\na language connector. If the environment variable does not exist, the system will get the secret key\nfrom the temporary local file system at /tmp/config/lang-api-key.txt\n\nIf /tmp/config/lang-api-key.txt does not exist, the system will create a random secret key automatically.\nIf the language connector and the python application are running in the same container, they will find each other\nwithout any configuration.\n\n## Distributed tracing\n\nMicroservices are likely to be deployed in a multi-tier environment. \nAs a result, a single transaction would pass through multiple layers of services.\n\nDistributed tracing allows us to visualize the complete service path for each transaction.\nThis enables easy trouble shooting for large scale applications.\n\nWith the Mercury framework, distributed tracing does not require coding at application level.\nTo enable this feature, you can simply set \"tracing=true\" in the rest.yaml configuration of\nthe rest-automation helper application.\n\n## Developer guide\n\nFor more details, please refer to the [Developer Guide](docs/guides/TABLE-OF-CONTENTS.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faccenture%2Fmercury-python","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faccenture%2Fmercury-python","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faccenture%2Fmercury-python/lists"}