{"id":28619658,"url":"https://github.com/eleme/doctor","last_synced_at":"2025-10-25T06:44:29.217Z","repository":{"id":145526821,"uuid":"54368591","full_name":"eleme/doctor","owner":"eleme","description":"Metric based in-memory circuit breaker for python","archived":false,"fork":false,"pushed_at":"2017-02-06T05:35:59.000Z","size":25,"stargazers_count":23,"open_issues_count":0,"forks_count":9,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-06-12T04:49:07.586Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","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/eleme.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":"2016-03-21T07:35:28.000Z","updated_at":"2022-04-15T03:19:14.000Z","dependencies_parsed_at":null,"dependency_job_id":"0a2db166-f6c8-4d51-a936-7a94c9612e0c","html_url":"https://github.com/eleme/doctor","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/eleme/doctor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eleme%2Fdoctor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eleme%2Fdoctor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eleme%2Fdoctor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eleme%2Fdoctor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eleme","download_url":"https://codeload.github.com/eleme/doctor/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eleme%2Fdoctor/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267144678,"owners_count":24042641,"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-07-26T02:00:08.937Z","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":"2025-06-12T04:40:54.085Z","updated_at":"2025-10-25T06:44:23.925Z","avatar_url":"https://github.com/eleme.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"## doctor\n\nHealth is described with current errors percentage, if the health status turns bad, actions like “refuse service” should be taken, mainly to protect our backend databases.\n\nYou must invoke `on_*` like methods of `doctor.checker.HealthTester.metrics`(`doctor.metrics.Metrics`) to record metrics, then `HealthTester.is_healthy` calculate api call status by thresholds, and `HealthTester.test` based the flowing policy to decide whether the current request can be passed.\n\n### Install\n\n    pip install git+https://github.com/eleme/doctor.git\n\n### Policy\n\nCurrent detail policy to test health description:\n\n- if current api is heavily under errors, disallow it to pass the test(), and further incoming requests should be refused ( in at least MIN_RECOVERY_TIME).\n- if current api has recoveried from bad health, allow it to pass the test() gradually (via random.random() with priority).\n\nCurrent errors threholds:\n\n- Errors contains system errors and gevent timeouts.\n- Threholds are percentages: errors / requests.\n- Errors threholds are checked only if the current requests count is greater than THRESHOLD_REQUEST.\n\nHealth check interval:\n\n- Calculated by METRICS_GRANULARITY * METRICS_ROLLINGSIZE, in seconds.\n\n### Settings\n\n```\nMIN_RECOVERY_TIME         min recovery time (in seconds)\nMAX_RECOVERY_TIME         max recovery time (in seconds)\nTHRESHOLD_REQUEST         min requests to trigger a health check. (per INTERVAL)  # noqa\nTHRESHOLD_TIMEOUT         gevent timeout count threshold (per INTERVAL)\nTHRESHOLD_SYS_EXC         sys_exc count threshold (per INTERVAL)\nTHRESHOLD_UNKWN_EXC       unkwn_exc count threshold (per INTERVAL)\n```\n\n### Examples\n\n```Python\n# callbacks, take *doctor.checker.APIHealthTestCtx* as arguments\ndef on_api_health_locked(result):\n    pass\ndef on_api_health_unlocked(result):\n    pass\ndef on_api_health_tested(result):\n    pass\ndef on_api_health_tested_bad(result):\n    pass\ndef on_api_health_tested_ok(result):\n    pass\n\n# you can custom the settings, see doctor/configs.py\nconfigs = Configs()\n\n# callbacks order matters.\ntester = HealthTester(\n    configs,\n    on_api_health_locked,\n    on_api_health_unlocked,\n    on_api_health_tested,\n    on_api_health_tested_bad,\n    on_api_health_tested_ok,\n)\n\n\ndef api_decorator(func):\n    @functools.wraps(func)\n    def _wrapper(service, *args, **kwargs):\n        service_name, func_name = service.name, func.__name__\n        if not tester.test(service_name, func_name):\n            print('Oh! No!!!')\n            return\n\n        result = None\n        try:\n            result = func(service, *args, **kwargs)\n        except UserError:\n            tester.metrics.on_api_called_user_exc(service_name, func_name)\n        except TimeoutError:\n            tester.metrics.on_api_called_timeout(service_name, func_name)\n        except SysError:\n            tester.metrics.on_api_called_sys_exc(service_name, func_name)\n        except Exception:\n            tester.metrics.on_api_called_unkwn_exc(service_name, func_name)\n        else:\n            tester.metrics.on_api_called_ok(service_name, func_name)\n        finally:\n            tester.metrics.on_api_called(service_name, func_name)\n\n        return result\n    return _wrapper\n\n\n@api_decorator\ndef api(service):\n    client.connect(service.addr)\n```\n\n### Ports\n\n- [Go](https://github.com/eleme/circuitbreaker)\n\n### Authors\n\n* @Damnever\n* @xiangyu.wang\n* @hit9\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feleme%2Fdoctor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feleme%2Fdoctor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feleme%2Fdoctor/lists"}