{"id":13647513,"url":"https://github.com/quantopian/coal-mine","last_synced_at":"2025-04-06T09:08:18.848Z","repository":{"id":28941217,"uuid":"32467082","full_name":"quantopian/coal-mine","owner":"quantopian","description":"Coal Mine - Periodic task execution monitor","archived":false,"fork":false,"pushed_at":"2024-08-14T18:18:58.000Z","size":278,"stargazers_count":113,"open_issues_count":2,"forks_count":37,"subscribers_count":17,"default_branch":"master","last_synced_at":"2024-10-30T00:10:28.110Z","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":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/quantopian.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}},"created_at":"2015-03-18T15:28:25.000Z","updated_at":"2024-10-05T18:09:05.000Z","dependencies_parsed_at":"2023-02-15T19:30:50.579Z","dependency_job_id":"9aaa2cd5-9bc1-485e-b815-34a021a011cc","html_url":"https://github.com/quantopian/coal-mine","commit_stats":{"total_commits":167,"total_committers":6,"mean_commits":"27.833333333333332","dds":"0.28742514970059885","last_synced_commit":"a4c0d0f43d6ab56a8a6ac33abc144d8fa24dae4b"},"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quantopian%2Fcoal-mine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quantopian%2Fcoal-mine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quantopian%2Fcoal-mine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quantopian%2Fcoal-mine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/quantopian","download_url":"https://codeload.github.com/quantopian/coal-mine/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247457801,"owners_count":20941906,"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":[],"created_at":"2024-08-02T01:03:37.046Z","updated_at":"2025-04-06T09:08:18.830Z","avatar_url":"https://github.com/quantopian.png","language":"Python","readme":"Coal Mine - Periodic task execution monitor\n===========================================\n\nHome page is [on Github](https://github.com/quantopian/coal-mine/).\nReleases are available [in PyPI](https://pypi.python.org/pypi/coal_mine).\nPlease support this project [on Patreon](https://patreon.com/jikseclecticofferings).\n\nWhat is Coal Mine?\n------------------\n\nPeriodic, recurring tasks are ubiquitous in computing, and so one of\nthe most common problems in systems administration and operations is\nensuring that such tasks execute as expected. Designing the tasks to\nreport errors is necessary but not sufficient; what if a task isn't\nbeing run at all (crashed daemon, misconfigured crontab) or is running\nmuch more slowly than it should be?\n\nCoal Mine provides a simple yet powerful tool for solving this\nproblem. In a nutshell:\n\n* Each recurring task has a Coal Mine \"canary\" associated with it.\n* The task triggers the canary when it is finished executing.\n* The canary knows how often the task is supposed to execute.\n* Coal Mine alerts by email when a canary is late and alerts again\n  when the late canary resumes.\n* Coal Mine keeps a (partial) history of when each canary was\n  triggered.\n\n\nTrack tasks that are supposed to execute periodically using \"canaries\"\nthat the tasks trigger when they execute. Alert by email when a canary\nis late. Alert again when a late canary resumes. Keep a partial\nhistory of canary trigger times.\n\nThe server notifies immediately when the deadline for an unpaused\ncanary passes. Similarly, the server notifies immediately when a\npreviously late canary is triggered.\n\nPrerequisites\n-------------\n\n* Python 3.2\n* MongoDB for storage (pull requests to add additional storage engines\n  are welcome)\n* requirements listed in requirements.txt\n* for development, requirements listed in requirements_dev.txt\n\nConcepts\n--------\n\nCoal Mine provides two interfaces, a REST API and a command-line\ninterface (CLI). Since triggering a canary requires nothing more than\nhitting its endpoint with a GET or POST query, it's best to do\ntriggering through the API, so that the CLI doesn't need to be\ninstalled on every system running monitoring tasks. For administrative\noperations, on the other hand, the CLI is usually easier.\n\nAll timestamps stored and displayed by Coal Mine are in UTC.\n\n### Operations\n\nThe operations that can be performed on canaries through the CLI or\nAPI are:\n\n* create\n* delete\n* reconfigure\n* get information about\n* pause -- stop monitoring and alerting\n* unpause\n* trigger\n* list -- all canaries or the ones matching search terms\n\nCoal Mine security is rudimentary. If the server is configured with an\noptional authentication key, then the key must be specified with all\noperations except trigger.\n\n### Data\n\nThese canary attributes are specified when it is created or updated:\n\n* name\n* description\n* periodicity -- the maximum number of seconds that can elapse before\n  a canary is late, _or_ a schedule in the format described\n  [below](#periodicity), which allows the periodicity of the canary to\n  vary over time\n* zero or more notification email address(es)\n\nThese are created and maintained by Coal Mine:\n\n* slug -- the canary's name, lower-cased, with spaces and underscores\n  converted to hyphens and other non-alphanumeric characters removed\n* a random identifier consisting of eight lower-case letters,\n  generated when the canary is created and guaranteed to be unique\n  against other canaries in the database\n* late state (boolean)\n* notify state (boolean) indicating whether a notification needs to be\n  sent out for this canary (used when notifications are being handled\n  by a separate background task)\n* paused state (boolean)\n* deadline by which the canary should be triggered to avoid being late\n* a history of triggers, pruned when \u003e1000 or (\u003e100 and older than one\n  week)\n\n#### Scheduled periodicity  \u003ca name=\"periodicity\"\u003e\u003c/a\u003e\n\nCoal Mine allows the periodicity of a canary to vary automatically\nbased on the time, date, day of week, etc. There are three contexts in\nwhich this is useful:\n\n1. a recurring task executes with different frequencies at different\n   times;\n2. a continuous recurring task takes more or less time to finish at\n   different times; or\n3. the urgency of responding to delays in a recurring task varies at\n   different times.\n\nTo specify a varying periodicity for a canary, instead of just\nspecifying a number of seconds, you specify a serious of\n[crontab-like directives](https://github.com/josiahcarlson/parse-crontab)\nseparated by semicolons. Here's an example, split onto multiple lines\nfor clarity:\n\n    # 5-minute delays are ok on weekends ;\n    * * * * sat,sun 300 ;\n    # 5-minute days are ok overnight ;\n    * 0-12 * * mon-fri 300 ;\n    # otherwise, we require a shorter periodicity ;\n    * 13-23 * * mon-fri 90\n\nNotes:\n\n* The last field in each directive is the periodicity value, i.e., the\n  maximum number of seconds to allow between triggers during the\n  specified time range.\n\n* As indicated above, even though the example is shown split across\n  multiple lines, it must be specified all on one line when providing\n  it to Coal Mine.\n\n* Note that comments like the ones shown above really are allowed in\n  the schedule you specify to Coal Mine -- they're not just for\n  decoration in the example -- but you need to remember to end them\n  with semicolons.\n\n* Schedule directives _cannot overlap_. For example, this won't work,\n  because the second directive overlaps with the first one every\n  Saturday and Sunday between midnight and noon:\n\n        * * * * sat,sun 60 ;\n        * 0-11 * * * 90\n\n* If a canary's schedule has gaps, then _the canary is effectively\n  paused_ during them. For example, in this schedule, the canary would\n  be paused all day Saturday:\n\n        * * * * sun 300 ;\n        * * * * mon-fri 60\n\n* As with everything else in Coal Mine, the hours and minutes\n  specified here are in UTC.\n\n* When you create or update a canary with a periodicity schedule, the\n  canary data returned to you in response will include a\n  \"periodicity_schedule\" field showing how the schedule you specified\n  plays out. The schedule will extend far enough into the future for\n  each of the directives you specified to be be shown at least once,\n  or for a week, whichever is longer.\n\nInstallation and configuration\n------------------------------\n\n### Server\n\n1. `pip install coal-mine`\n2. Create `/etc/coal-mine.ini` (see [below](#ini-file)) or [use\n   environment variables](#env-vars-config)\n3. Run `coal-mine \u0026`\n4. Put that in `/etc/rc.local` or something as needed to ensure that\n   it is restarted on reboot.\n\n#### Server configuration file  \u003ca name=\"ini-file\"\u003e\u003c/a\u003e\n\nThe server configuration file, `coal-mine.ini`, can go in the current\ndirectory where the server is launched, `/etc`, or\n`/usr/local/etc`. (If you need to put it somewhere else, modify the\nlist of directories near the top of `main()` in `server.py`.)\n\nThe file is (obviously) in INI format. Here are the sections and\nsettings that it can or must contain:\n\n* \\[logging\\] -- optional\n  * file -- log file path; otherwise logging goes to stderr\n  * rotate -- if true, then rotate the log file when it gets too large\n  * max\\_size -- max log file size before rotating (default: 1048576)\n  * backup\\_count -- number of rotated log files to keep (default: 5)\n* \\[mongodb\\] -- required\n  * hosts -- MongoDB URI or comma-separated list of one or more host\n    names\n  * database -- database name. Coal Mine will create only one\n    collection in the database, called \"canaries\". Omit if\n    `hosts` contains a MongoDB URI\n  * username -- omit if no authentication is required or `hosts`\n    contains a URI\n  * password -- omit if no authentication is required or if `hosts`\n    contains a URI\n  * replicaSet -- must be specified if using a replicaset and `hosts`\n    isn't a URI\n  * other arguments will be passed through to MongoClient\n     * for example, tls can be set to True or False\n* \\[email\\]\n  * sender (required) -- email address to put in the From line of\n    notification emails\n  * host (optiona) -- SMTP host to connect to\n  * port (optional) -- SMTP port to connect to\n  * username (optional) -- SMTP username, must be specified if\n    password is\n  * password (optional) -- SMTP password, must be specified if\n    username is\n* \\[wsgi\\] -- optional\n  * port -- port number the server should listen on (default: 80)\n  * auth\\_key -- if non-empty, then the specified key must be\n    specified as a parameter of the same name with all API requests\n    except \"trigger\".\n\n#### Configurating via environment variables  \u003ca name=\"env-vars-config\"\u003e\u003c/a\u003e\n\nIf the environment variable `MONGODB_URI` is set, then the server will\nread its configuration from environment variables _instead of_\n`coal-mine.ini`. (i.e., the configuration file will neither be\nsearched for nor read). When configured this way, logging\nconfiguration is not supported, the `mongodb` configuration file\nsection is replaced with the `MONGODB_URI` variable, and the remaining\nconfiguration settings are specified as follows:\n\n* email.sender -\u003e `EMAIL_SENDER`\n* email.host -\u003e `SMTP_HOST`\n* email.port -\u003e `SMTP_PORT`\n* email.username -\u003e `SMTP_USERNAME`\n* email.password -\u003e `SMTP_PASSWORD`\n* wsgi.port -\u003e `WSGI_PORT`\n* wsgi.auth_key -\u003e `WSGI_AUTH_KEY`\n\n### Deploying the Server to Heroku\n\nThere's a `Procfile` in the source tree which allows you to deploy\nthis app to Heroku. This is new functionality which has not been\nextensively tested, so please [file bug reports][bugs] if you run into\nany issues! Here's how to do it in a nutshell:\n\n[bugs]: https://github.com/quantopian/coal-mine/issues\n\n1. Create a new Heroku app to hold it.\n2. Connect a MongoDB database to the Heroku app via the `MONGODB_URI`\n   config variable, via an add-on (I think ObjectRocket will work?),\n   MongoDB Atlas, your own self-hosted MongoDB cluster, or whatever.\n   It doesn't matter where the MongoDB database lives as long as\n   Heroku can connect to it and its full URI is in `MONGODB_URI`.\n3. Set `EMAIL_SENDER`, `SMTP_HOST`, `SMTP_PORT`, `SMTP_USERNAME`,\n   `SMTP_PASSWORD`. You'll need to add an SMTP add-on to the Heroku\n   app or have an SMTP server somewhere else you can use; if you use\n   an add-on, it'll probably call these settings by different names,\n   so you'll have to copy them into the names that Coal Mine expects.\n4. Set `WSGI_AUTH_KEY` to something long and random, since you don't\n   want anyone on the internet to be able to mess with your Coal Mine\n   instance.\n5. Push the code to the Heroku app.\n6. Make sure the app is configured to run at least one web dyno\n   (should happen by default) and exactly 1 worker dyno.\n\nOnce all that's done you'll need to configure your CLI to talk to the\nHeroku app as described below. Make sure to specify `https://` at the\nstart of the host name when configuring the CLI.\n\n### CLI\n\n1. `pip install coal-mine`\n2. `cmcli configure [--host server-host-name] [--port server-port]\n        [--auth-key key | --no-auth-key]`\n\nThe `--host` argument can take a URL base (i.e.,\n`http://server-host-name` or `https://server-host-name`) as well. This\nis useful if, for example, you've put your Coal Mine server behind an\nSSL proxy so the CLI needs to use SSL to connect to it (which you\nprobably will, e.g., if you are deploying to Heroku as described\nabove).\n\nThe CLI stores its configuration in `~/.coal-mine.ini`. Note that the\nauthentication key is stored in plaintext. Any configuration\nparameters the CLI needs that aren't stored in the INI file must be\nspecified explicitly on the command line when using the CLI.\n\nUsing Coal Mine\n---------------\n\n### CLI\n\nThe Coal Mine CLI, `cmcli`, provides convenient access to the full\nrange of Coal Mine's functionality.\n\nTo make the CLI easier to use, you can configure it as shown above,\nbut you also have the option of specifying the server connection\ninformation every time you use it. Also, connnection information\nspecified on the command line overrides the stored configuration.\n\nHere are some example commands:\n\n    cmcli create --help\n    \n    cmcli create --name 'My Second Canary' --periodicity $((60*60*25))  # $((60*60*25)) is 25 hours\n    cmcli trigger --id aseprogj\n    cmcli delete --slug 'my-second-canary'\n\nRun `cmcli --help` for more information.\n\nFor commands that operate on individual canaries, you can identify the\ncanary with `--id`, `--name`, or `--slug`. Note that for the `update`\ncommand, if you want to update the name of a canary you will need to\nidentify it `--id` or `--slug`, because in that case the `--name`\nargument is used to specify the new name.\n\nAPI usage examples\n------------------\n\n### Example commands\n\n    $ coal-mine \u0026\n    [1] 7564\n    $ curl 'http://coal-mine-server/coal-mine/v1/canary/create?name=My+First+Canary\u0026periodicity=3600'\n    {\n        \"status\": \"ok\",\n        \"canary\": {\n            \"deadline\": \"2015-03-19T02:08:44.885182\",\n            \"id\": \"fbkvlsby\",\n            \"paused\": false,\n            \"description\": \"\",\n            \"periodicity\": 3600,\n            \"name\": \"My First Canary\",\n            \"slug\": \"my-first-canary\",\n            \"emails\": [],\n            \"history\": [\n                [\n                    \"2015-03-19T01:08:44.885182\",\n                    \"Canary created\"\n                ]\n            ],\n            \"late\": false\n        }\n    }\n    $ curl 'http://coal-mine-server/fbkvlsby?comment=short+form+trigger+url'\n    {\n        \"recovered\": false,\n        \"unpaused\": false,\n        \"status\": \"ok\"\n    }\n    $ curl 'http://coal-mine-server/coal-mine/v1/canary/trigger?slug=my-first-canary\u0026comment=long+form+trigger+url'\n    {\n        \"recovered\": false,\n        \"unpaused\": false,\n        \"status\": \"ok\"\n    }\n    $ curl 'http://coal-mine-server/coal-mine/v1/canary/get?name=My+First+Canary'\n    {\n        \"canary\": {\n            \"paused\": false,\n            \"name\": \"My First Canary\",\n            \"history\": [\n                [\n                    \"2015-03-19T01:11:56.408000\",\n                    \"Triggered (long form trigger url)\"\n                ],\n                [\n                    \"2015-03-19T01:10:42.608000\",\n                    \"Triggered (short form trigger url)\"\n                ],\n                [\n                    \"2015-03-19T01:08:44.885000\",\n                    \"Canary created\"\n                ]\n            ],\n            \"emails\": [],\n            \"id\": \"fbkvlsby\",\n            \"late\": false,\n            \"slug\": \"my-first-canary\",\n            \"deadline\": \"2015-03-19T02:11:56.408000\",\n            \"periodicity\": 3600,\n            \"description\": \"\"\n        },\n        \"status\": \"ok\"\n    }\n\nAll API endpoints are fully documented below.\n\n### Watching a cron job\n\n     0 0 * * * my-backup-script.sh \u0026\u0026 (curl http://coal-mine-server/fbkvlsby \u0026\u003e/dev/null)\n\nAPI reference\n-------------\n\nAll API endpoints are submitted as http(s) GET requests. Results are\nreturned in JSON.\n\nAll results have a \"status\" field which is \"ok\" on success or \"error\"\non failure. Failures also return a reasonable HTTP error status code.\n\nBoolean fields in API should be specified as \"true\", \"yes\", or \"1\" for\ntrue, or \"false\", \"no\", \"0\", or empty string for false. Boolean fields\nin responses are standard JSON, i.e., \"true\" or \"false\".\n\nTimestamps returned by the API are always UTC.\n\n### Create canary\n\nEndpoint: `/coal-mine/v1/canary/create`\n\nSide effects:\n\nAdds canary to database. Creates history record at current time with\n\"Canary created\" as its comment. Sets deadline to current time plus\nperiodicity, unless \"paused\" was specified.\n\nRequired parameters:\n\n* name\n* periodicity\n* auth\\_key (if authentication is enabled in the server)\n\nOptional parameters:\n\n* description - empty if unspecified\n* email - specify multiple times for multiple addresses; no\n  notifications if unspecified\n* paused - allows canary to be created already in paused state\n\nResponse is the same as shown for get().\n\n### Delete canary\n\nEndpoint: `/coal-mine/v1/canary/delete`\n\nRequired parameters:\n\n* name, id, or slug\n* auth\\_key\n\nResponse:\n\n    {'status': 'ok'}\n\n### Update canary\n\nEndpoint: `/coal-mine/v1/canary/update`\n\nSide effects:\n\nUpdates the specified canary attributes. Updates deadline to latest\nhistory timestamp plus periodicity if periodicity is updated and\ncanary is unpaused, and sets late state if new deadline is before\nnow. Sends notification if canary goes from not late to late or vice\nversa.\n\nRequired parameters:\n\n* id or slug (_not_ name, which should only be specified to update the\n  name and slug)\n* auth\\_key\n\nOptional parameters:\n\n* name\n* periodicity\n* description\n* email - specify a single value of \"-\" to clear existing email addresses\n\nResponse is the same as shown for get().\n\n### Get canary\n\nEndpoint: `/coal-mine/v1/canary/get`\n\nRequired parameters:\n\n* name, id, or slug\n* auth\\_key\n\nResponse:\n\n    {'status': 'ok',\n     'canary': {'name': name,\n               'description': description,\n               'id': identifier,\n               'slug': slug,\n               'periodicity': seconds,\n               'emails': [address, ...],\n               'late': boolean,\n               'paused': boolean,\n               'deadline': 'YYYY-MM-DDTHH:MM:SSZ',\n               'history': [['YYYY-MM-DDTHH:MM:SSZ', comment], ...]}}\n\n### List canaries\n\nEndpoint: `/coal-mine/v1/canary/list`\n\nRequired parameters:\n\n* auth\\_key\n\nOptional parameters:\n\n* verbose - include all query output for each canary\n* paused - boolean, whether to list paused / unpaused canaries only\n* late - boolean, whether to list late / timely canaries only\n* search - string, regular expression to match against name, identifier, and\n  slug\n\nResponse:\n\n    {'status': 'ok',\n     'canaries': [{'name': name,\n                 'id': identifier},\n                ...]}\n\nIf \"verbose\" is true, then the JSON for each canary includes all the\nfields shown above, not just the name and identifier.\n\n### Trigger canary\n\nEndpoint: `/coal-mine/v1/canary/trigger`\n\nAlso: /_identifier_, in which case the \"id\" parameter is implied\n\nNote that the server will accept POST requests for triggers as well as\nGET requests, so that you can use triggers as webhooks in applications\nthat expect to be able to POST. The content of the POST is ignored;\neven when using POST, the API parameters must still be specified as a\nquery string.\n\nSide effects:\n\nSets late state to false. Sets deadline to now plus periodicity. Adds\nhistory record. Prunes history records. Unpauses canary. Generates\nnotification email if canary was previously late.\n\nRequired parameters:\n\n* name, id, or slug\n\nOptional parameters:\n\n* comment - stored in history with trigger record\n\nResponse:\n\n    {'status': 'ok', 'recovered': boolean, 'unpaused': boolean}\n\n* recovered - indicates whether the canary was previously late before\n  this trigger\n* unpaused - indicates whether the canary was previously paused before\n  this trigger\n\n### Pause canary\n\nEndpoint: `/coal-mine/v1/canary/pause`\n\nSide effects:\n\nClears deadline. Sets late state to false if necessary. Pauses\ncanary. Adds history record about pause. Prunes history records.\n\nRequired parameters:\n\n* name, id, or slug\n* auth\\_key\n\nOptional parameters:\n\n* comment\n\nResponse is the same as shown for get().\n\n### Unpause canary\n\nEndpoint: `/coal-mine/v1/canary/unpause`\n\nSide effects:\n\nSets deadline to now plus periodicity. Unpauses canary. Adds history\nrecord about unpause. Prunes history records.\n\nRequired parameters:\n\n* name, id, or slug\n* auth\\_key\n\nOptional parameters:\n\n* comment\n\nResponse is the same as shown for get().\n\nQuis custodiet ipsos custodes?\n------------------------------\n\nObviously, if you're relying on Coal Mine to let you know when\nsomething is wrong, you need to make sure that Coal Mine itself stays\nrunning. One way to do that is to have a cron job which periodically\ntriggers a canary and generates output (which crond will email to you)\nif the trigger fails. Something like:\n\n    0 * * * * (curl http://coal-mine-server/atvywzoa | grep -q -s '\"status\": \"ok\"') || echo \"Failed to trigger canary.\"\n\nI also recommend using a log-monitoring service such as Papertrail to\nmonitor and alert about errors in the Coal Mine log.\n\nContacts\n--------\n\n[Github](https://github.com/quantopian/coal-mine)\n\n[Email](mailto:jik@kamens.us)\n\n[PyPI](https://pypi.python.org/pypi/coal_mine)\n\nContributors\n------------\n\nCoal Mine was created by Jonathan Kamens, with design help from the\nawesome folks at [Quantopian](https://www.quantopian.com/). Thanks,\nalso, to Quantopian for supporting the development and open-sourcing\nof this project.\n\nMaintaining the package\n-----------------------\n\n### Tests\n\nTests are expecting to be run with `pytest`. With all the packages in\n`requirements.txt` and `requirements_dev.txt` installed, run `python3\n-m pytest`.\n\n### Building\n\nAfter installing the requirements in `requirements.txt` and\n`requirements_dev.txt`, do `python3 -m build` to build packages.\n\n### Uploading to PyPI\n\nWe're currently using Twine for uploading to PyPI. You need to install the\nrequirements in `requirements.txt` and `requirements_dev.txt` in order\nto use it. You also need to configure it. See the [Twine\ndocumentation](https://twine.readthedocs.io/en/stable/) for more info.\n\nDevelopment philosophy\n----------------------\n\nUse Python.\n\nDo one, simple thing well. There are several similar projects out\nthere that do more than this project attempts to do.\n\nMake the implementation as simple and straightforward as possible. The\ncode should be small. What everything does should be obvious from\nreading it.\n\nMinimize external dependencies. If something is simple and\nstraightforward to do ourselves, don't use a third-party package just\nfor the sake of using a third-party package.\n\nAlternatives\n------------\n\nAlternatives to Coal Mine include:\n\n* [Dead Man's Snitch](https://deadmanssnitch.com/)\n* [Cronitor.io](https://cronitor.io/)\n* [Sheriff](https://github.com/dawanda/sheriff)\n\nWe chose to write something new, rather than using what's already out\nthere, for several reasons:\n\n* We wanted more control over the stability and reliability of our\n  watch service than the commercial alternatives provide.\n* We wanted fine-grained control over the periodicity of our watches,\n  as well as assurance that we would be notified immediately when a\n  watch is late, something that not all of the alternatives\n  guarantee.\n* We like Python.\n* We like OSS.\n\n### To Do\n\n(Pull requests welcome!)\n\nOther storage engines.\n\nOther notification mechanisms.\n\nWeb UI.\n\nLinks to Web UI in email notifications.\n\nRepeat notifications if a canary remains late for an extended period\nof time? Not even sure I want this.\n\nBetter authentication?\n\nSupport time-zone localization of displayed timestamps.\n\nSSL support in server\n","funding_links":["https://patreon.com/jikseclecticofferings"],"categories":["Python"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fquantopian%2Fcoal-mine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fquantopian%2Fcoal-mine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fquantopian%2Fcoal-mine/lists"}