{"id":15598491,"url":"https://github.com/kevindasilvas/hookme","last_synced_at":"2025-07-23T09:05:37.555Z","repository":{"id":192701409,"uuid":"674826945","full_name":"KevinDaSilvaS/hookme","owner":"KevinDaSilvaS","description":"Async data fetch and sender built with Elixir","archived":false,"fork":false,"pushed_at":"2023-08-06T23:07:46.000Z","size":368,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-29T12:14:02.724Z","etag":null,"topics":["elixir","elixir-lang","httpoison","plug"],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/KevinDaSilvaS.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2023-08-04T22:22:04.000Z","updated_at":"2024-07-13T16:05:43.000Z","dependencies_parsed_at":null,"dependency_job_id":"376fca6c-01b8-4a51-987f-0c37ada2eeef","html_url":"https://github.com/KevinDaSilvaS/hookme","commit_stats":{"total_commits":49,"total_committers":1,"mean_commits":49.0,"dds":0.0,"last_synced_commit":"7130cd5de524b42acd7839bf38dc10b3db92cd8a"},"previous_names":["kevindasilvas/hookme"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/KevinDaSilvaS/hookme","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KevinDaSilvaS%2Fhookme","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KevinDaSilvaS%2Fhookme/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KevinDaSilvaS%2Fhookme/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KevinDaSilvaS%2Fhookme/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/KevinDaSilvaS","download_url":"https://codeload.github.com/KevinDaSilvaS/hookme/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KevinDaSilvaS%2Fhookme/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266649141,"owners_count":23962178,"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-23T02:00:09.312Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"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":["elixir","elixir-lang","httpoison","plug"],"created_at":"2024-10-03T01:40:23.283Z","updated_at":"2025-07-23T09:05:37.536Z","avatar_url":"https://github.com/KevinDaSilvaS.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Hookme\n\n## Instalação\n  No projeto consta um arquivo docker-compose.yml caso possua o docker instalado basta rodar:\n```\ndocker-compose up -d --build\n```\n Para rodar manualmente é necessario instalar as dependencias:\n ```\nmix deps.get\n```\nE rodar:\n```\nmix run --no-halt\n```\n\n## Sobre os envs\nNo arquivo docker-compose.yml existe uma série de variaveis que podemos usar para customizar a aplicação:\n - **SCHEDULE_INTERVAL** -\u003e *Representa o tempo de assincronicidade da request em milisegundos, ou seja quanto um processo vai precisar esperar para enviar as informações para o webhook*\n - **RESCHEDULE_INTERVAL** -\u003e *Representa quanto tempo um processo de retentativa vai esperar em milisegundos, caso a primeira request falhe podemos setar a retentativa para occorrer x milisegundos após a primeira*\n - **RETRY_MAX_ATTEMPTS** -\u003e *Representa quantas retentativas a aplicação tentará fazer para uma determinada task*\n - **WEBHOOK_URL** -\u003e *A url do webhook para qual vamos mandar as informações nos jobs*\n - **API_URL** -\u003e *Link para a api desejada, no caso o link da api do github*\n - **API_TOKEN** -\u003e *Caso queira autenticar na api do github coloque o seu token de acesso aqui, caso queira usar a api do github sem autenticar apenas deixe essa variavel como: \"\"*\n - **RATE_LIMIT_MAX_SIMULTANEOUS_JOBS** -\u003e *Caso queira adicionar um rate limit para não permitir que a aplicação tenha mais de X jobs assincronos rodando sete a variavel para um numero inteiro de sua preferencia, caso não queira usar o rate limit apenas deixe essa variavel como: -1*\n\n## Sobre os endpoints\nA aplicação possui apenas um endpoint */tasks* \n  - **[POST]** *http://localhost:4001/tasks*\n    - ```\n        {\n        \t\"username\": \"KevinDaSilvaS\",\n        \t\"repository\": \"duper\"\n        }\n      ```\n\n## Sobre o fluxo da arquitetura\n  ![architecture flow](./arch-complete.png \"architecture flow\")\n  \n## Sobre as escolhas tecnicas\nQuando surge o desafio de criar um serviço para agregar informações de uma serie de endpoint e envia-los de forma assincrona começamos a pensar nas tecnologias, e quais seriam o estado da arte e as primeiras que nos veem a mente são\n - **phoenix** o canhão do desenvolvimento web com alta gama de funcionalidades\n - **oban** para rodar diversos jobs assincronos e com retry e alta resiliencia\n - **ETS** para um caching super eficiente na maquina virtual do Erlang\n\n#\n\nMas analisando mais cuidadosamente o problema fiz as seguintes perguntas:\n - Vou lidar com muitos endpoints, sockets, channels e tudo o que há de bom?\n     - Resposta: Não na verdade só terei um endpoint para enviar o **username** e o **repository** então uma abordagem mais simples talvez deva ser usar o **Plug** ao invés do phoenix pela simplicidade ao mesmo tempo em que o Plug é a base do phoenix que nada mais é que uma composição de simples plugs\n - A abordagem mais simples inicialmente é usar Oban com todo o tempo inicial de configuração e de adicionar um Postgres?\n     - Resposta: Não, na verdade a maneira mais simples e incremental seria usar o modulo Task e criar uma task assincrona para cada job e adicionar uma politica de retentativa caso uma task não consiga finalizar com sucesso o envio de dados para o webhook\n - Manter um caching de usuarios/repositorios para evitar ddos e tambem manter um caching de usuarios buscados na api do github é muito essencial para performance, mas precisamos iniciar com um ETS?\n     - Resposta: Como não vamos iniciar de maneira mais robusta em mais de uma maquina podemos tomar uma abordagem de usar Agents para o controle de informações visto que é a finalidade desse modulo guardar estados e se necessario adicionar um maximo de jobs no cache\n\n## Validações extras\n  - [Impedir duplicadas] - Hoje se guarda cada job/task com uma chave *${username}/${repository}* com a intenção de impedir eventual ddos de multiplos jobs para o mesmo usuario e repositorio, então hoje só é permitido um job/task simultaneo para o mesmo usuario/repositorio\n  - [Impedir aobrecarga] - Pode se adicionar um rate limit na aplicação impedindo-a de criar mais de X jobs assincronos simultaneos\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkevindasilvas%2Fhookme","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkevindasilvas%2Fhookme","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkevindasilvas%2Fhookme/lists"}