{"id":18412072,"url":"https://github.com/elliotxx/watchman","last_synced_at":"2025-04-07T11:31:48.957Z","repository":{"id":43757129,"uuid":"212727867","full_name":"elliotxx/watchman","owner":"elliotxx","description":":calendar: 更夫（watchman）是一款可视化的定时任务配置 Web 工具，麻麻不用担心我漏掉任何更新啦！","archived":false,"fork":false,"pushed_at":"2022-02-19T12:41:52.000Z","size":1813,"stargazers_count":55,"open_issues_count":8,"forks_count":14,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-22T17:02:38.040Z","etag":null,"topics":["cron","crontab","gin","go","golang","react","schedule","sqlite"],"latest_commit_sha":null,"homepage":"http://watchman-demo.yangyingming.com","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/elliotxx.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}},"created_at":"2019-10-04T03:19:15.000Z","updated_at":"2025-02-10T05:08:33.000Z","dependencies_parsed_at":"2022-08-21T20:20:21.435Z","dependency_job_id":null,"html_url":"https://github.com/elliotxx/watchman","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elliotxx%2Fwatchman","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elliotxx%2Fwatchman/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elliotxx%2Fwatchman/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elliotxx%2Fwatchman/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elliotxx","download_url":"https://codeload.github.com/elliotxx/watchman/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247644232,"owners_count":20972249,"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":["cron","crontab","gin","go","golang","react","schedule","sqlite"],"created_at":"2024-11-06T03:39:37.550Z","updated_at":"2025-04-07T11:31:48.012Z","avatar_url":"https://github.com/elliotxx.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"## 简介\n\n[![GitHub release](https://img.shields.io/github/release/elliotxx/watchman.svg)](https://github.com/elliotxx/watchman/releases)\n[![Github All Releases](https://img.shields.io/github/downloads/elliotxx/watchman/total.svg)](https://github.com/elliotxx/watchman/releases)\n[![license](https://img.shields.io/github/license/elliotxx/watchman.svg)](https://github.com/elliotxx/watchman/blob/master/LICENSE)\n\n更夫（watchman）是一款可视化定时任务配置工具，集成有Web端交互界面、正则表达式解析、定时任务、邮件提醒、模板定制等功能。\n\n简单来说，Watchman 是一个 Web 应用程序，可以可视化的配置定时任务，通过指定抓取规则定时获取最新内容，如果有更新，就发送邮件通知。\n\n最开始要解决的需求是希望监控我正在看的网络小说的更新情况，一有更新就发邮件通知我。最初用 crontab + Python 脚本就能满足需求，但是时间长了发现配置新的监控目标和通知账号都要直接改代码，有些麻烦，于是就有了这个项目。\n\nWatchman 采用前后端分离设计，数据库采用 Sqlite3，整体十分轻量，并可用 Docker 一键部署。\n\n设计思路见：[一个基于 Golang + React 的定时任务可视化配置网站的设计与实现](http://yangyingming.com/article/454/)\n\n在线 Demo：[http://watchman-demo.yangyingming.com](http://watchman-demo.yangyingming.com)\n\n**默认登录账号：admin 密码：12345**\n\n## 预览\n配置定时抓取任务\n\n![](http://picgo.yangyingming.com/blog-454-list.png)\n\n定时任务编辑页面\n![](http://picgo.yangyingming.com/blog-454-edit.png)\n\n配置通知账户（Email）\n\n![](http://picgo.yangyingming.com/blog-454-email.png)\n\n更新时收到邮件通知\n\n![](http://picgo.yangyingming.com/blog-454-get-email.png)\n\n## 特性\n- 定时任务 创建/暂停/开始/编辑/删除\n- 通知账号 创建/编辑/删除\n- 通知账号（Email账号密码）有效性在线测试\n- 正则表达式在线测试\n- 前端实时查看日志\n- 定时模板（自动填充一些内容，比如抓取规则、邮件发送内容等）\n\n## 依赖\n* 前端: React（AntDesign）\n* 后端: Golang 1.12\n* web 框架: Gin 1.4\n* 数据库: Sqlite3\n\n## 运行\n使用 go modules 安装后端依赖 \u0026 运行后端\n```\ncd api\ngo mod tidy\ngo run cmd/main.go\n```\n使用 npm 安装前端依赖\n```\ncd ui\nnpm install\nnpm start\n```\n\n## 用 Docker 运行\n### 使用 Dockerfile 构建镜像\n```\ndocker build -f Dockerfile -t watchman .\ndocker run -d -p 8007:80 --name=watchman watchman\n```\n浏览器访问 ```127.0.0.1:8007``` 查看效果\n\n### 直接拉取镜像\n使用官方 Docker hub 拉取镜像（可能有些慢）\n```\ndocker pull elliotxx/watchman\ndocker run -d -p 8007:80 --name=watchman elliotxx/watchman\n# 指定数据盘挂载目录 示例\ndocker run -d -p 8007:80 -v /home/yym/watchman/data:/data --name=watchman elliotxx/watchman\n```\n\n或者使用 阿里云容器镜像服务 拉取镜像（国内加速）\n\n```\ndocker pull registry.cn-shanghai.aliyuncs.com/elliotxx/watchman\ndocker run -d -p 8007:80 --name=watchman registry.cn-shanghai.aliyuncs.com/elliotxx/watchman\n# 指定数据盘挂载目录 示例\ndocker run -d -p 8007:80 -v /home/yym/watchman/data:/data --name=watchman registry.cn-shanghai.aliyuncs.com/elliotxx/watchman\n```\n浏览器访问 ```127.0.0.1:8007``` 查看效果\n\n## 开启权限认证\n部署成功后，默认没有开启权限认证，也就是说接口都可以公开访问。\n\n如果要开启权限认证，请修改配置，采用 BasicAuth 进行认证。\n\n配置修改位置在 ```api/api/config.go L24```：\n```\nvar IsBasicAuth = false // 修改这里开启权限控制（调用接口需要输入用户名 \u0026 密码）\nvar Secrets \t= map[string]string{    // 默认登录账户\n\t\"admin\": \"12345\",\n}\n```\n\n## 笔记\n### docker 镜像加速\n鉴于国内网络问题，后续拉取 Docker 镜像十分缓慢，我们可以需要配置加速器来解决，网易的镜像地址：http://hub-mirror.c.163.com。\n\n配置以下文件，设置 docker 镜像仓库代理（如果没有该文件，就创建一个）：\n```\n# linux\nvi /etc/docker/daemon.json\n# windows\n%programdata%\\docker\\config\\daemon.json 或者 %USERPROFILE%\\.docker\\daemon.json\n# mac\n~/.docker/daemon.json\n```\n\n请在该配置文件中加入：\n```\n{\n  \"registry-mirrors\": [\"http://hub-mirror.c.163.com\",\"https://registry.docker-cn.com\"]\n}\n```\n\n### windows docker 安装\nwindows docker 比较麻烦，有两种方式。一种是 docker toolbox，另一种是 docker for windows\n\n推荐使用 docker toolbox，比较简单，国内可以使用阿里云的镜像来下载，下载地址：\n\nhttp://mirrors.aliyun.com/docker-toolbox/windows/docker-toolbox/\n\n装好之后，点击 \"开始 =\u003e Docker Quickstart Terminal\"，即可运行\n\n注意：如果点击 Docker Quickstart Terminal 弹出“找不到 bash”，需要你手动指定 git bash 的安装位置，比如我的就是：“D:\\Program Files\\Git\\bin\\bash.exe”\n\n\n### go-sqlite3 需要在编译时开启 cgo 才能工作\n否则报错：Binary was compiled with 'CGO_ENABLED=0', go-sqlite3 requires cgo to work.\n解决：\n编译时打开 CGO 开关：CGO_ENABLED=1\n\n\n### standard_init_linux.go:178: exec user process caused \"no such file or directory\"\ngolang docker build 制作完进项后运行报错\n\n出现该问题的原因是编译的环境和运行的环境不同，可能有动态库的依赖\n\n１．默认go使用静态链接，在docker的golang环境中默认是使用动态编译。\n\n２．如果想使用docker编译+alpine部署，可以通过禁用cgoCGO_ENABLED=0来解决。\n\n３．如果要使用cgo可以通过go build --ldflags \"-extldflags -static\" 来让gcc使用静态编译。\n\nref: https://www.cnblogs.com/davygeek/p/10969434.html\n\n\n### 使用 docker toolbox 主机无法用localhost访问 只能通过默认的宿主ip\n背景：在 Docker Quickstart Terminal 中运行 ```docker run -d -p 8080:8080 watchman-test:latest``` 启动一个容器的时候，我期望在浏览器中输入 ```127.0.0.1:8080``` 便可以看到容器中 webapp 的返回结果，但却访问不到该地址\n\n原因：因为 docker toolbox 默认是跑在 virtualbox 中的，而 virtualbox 中做了端口转发的限制，所以默认情况下我设置的端口在外网都是访问不到的\n\n解决：打开 virtualbox 会发现有个名叫 default 的虚拟机正在运行，docker toolbox 就跑在这上面，然后依次点击 \"default 右键设置 =\u003e 网络 =\u003e 网卡1 =\u003e 高级 =\u003e 端口转发\"，添加一条：\"Rule 1 | TCP | 127.0.0.1 | 8080 | | 8080\"\n\n再在浏览器中访问一下，是不是可以了呢\n\nref: https://blog.csdn.net/qq_36760953/article/details/83303322\n\n\n### 同一个 docker 容器中，如何同时运行两个进程\n背景：\n在同一个容器中，同时部署了前后端程序，前端需要 nginx，后端程序也要运行，这就要求两个进程同时运行\n\n但是我试过用 ```RUN xxx \u0026``` 和 ```ENTRYPOINT [\"nginx\", \"-g\", \"daemon off;\"]``` 组合的方式，一个通过 RUN 运行，一个用 ENTRYPOINT 容器启动时运行，但是不知道为什么用 RUN 运行的程序没有启动起来。\n\n所以只能想办法用 ENTRYPOINT 同时运行这两个程序\n\n解决：\n解决方法是把两个程序的启动命令都放到一个启动脚本里，然后再 ENTRYPOINT 中运行这个脚本，启动脚本最后跑一个死循环，这样可以保证容器一直运行。\n\n注意这两个程序的输出都写入到日志文件当中，然后把日志文件所在目录通过 VOLUME 方式挂载出来，这样可以防止日志文件在容器中增量到过大。\n\nrun.sh 启动脚本样例：\n```\n#!/bin/bash\n \n# run watchman\nwatchman \u003e /data/watchman.log 2\u003e\u00261 \u0026\n# run nginx\nnginx -g 'daemon off;' \u003e /data/nginx.log 2\u003e\u00261 \u0026\n \n# just keep this script running\nwhile [[ true ]]; do\n    sleep 1\ndone\n```\n\n\n### 同一个 docker 容器中，前后端分离部署，跨域访问的解决方案\n背景：\n在同一个容器中，同时部署了前后端程序，前端通过 nginx 转发 80 端口进行访问，后端运行在 8080 端口。\n\n前端中有 ajax 请求需要访问后端提供的接口，这个时候就会产生跨域请求问题，用户在浏览器访问前端然后请求 127.0.0.1:8080 显然是不合理的，除非再开启一个后端容器单独跑在 8080 端口，但是这样又背离了部署在同一个容器的初衷。\n\n解决：\n解决办法就是在后端接口加上 /api/v1/ 前缀，然后设置 nginx location 代理 /api/v1 到 8080 端口\n```\nlocation /api/v1 {\n    proxy_pass   http://127.0.0.1:8080;\n}\n```\n这样前后端请求都是通过 80 端口进入容器，只不过容器中的 nginx 转发了其中的 /api/v1 前缀的请求到后端 8080 端口\n\n\n### 前端中使用 react-router-dom 在浏览器中直接输入 url 无法访问的问题\n背景：\n前端中使用 react-router-dom 做路由，但是同样的 url 在路由页点击可以正常切换，在浏览器中输入 url 就无法访问了\n\n原因：\nrouter 设置的路由链接不是真实的链接，需要通过访问路由页 js 才能做转发，直接访问 url 其实是不存在这个资源的\n\n解决：\n将 BrowserRouter 修改为 HashRouter 即可解决，即：\n```\nimport {BrowserRouter as Router,Route,Link} from 'react-router-dom'\n```\n修改为：\n```\nimport {HashRouter as Router,Route,Link} from 'react-router-dom';\n```\n\nHashRouter 会在 url 前加一个 #，其实就是通过标签的方式标记了对应 url\n\nref：https://segmentfault.com/q/1010000012959395\n\n\n### nginx 启用 gzip 压缩 js 等文件\n背景：\n发现前端程序用 npm build 之后产生的 js 文件也有 400k，浏览器第一次访问需要 40s 才能加载出来\n\n解决：\n在 nginx 中启动 gzip 压缩 js 等文件，速度提升一半\n\nref：https://blog.csdn.net/kwy15732621629/article/details/78475021\n\n### 运行镜像报 dns 相关错误：device or resource busy\n原因是 docker 在 Dockerfile 中运行 docker build 的时候，会产生一些 dns 问题\n\n在 Dockerfile 中添加一下环境变量，设置 go 语言的默认 dns 解析采用纯 go 的方式（另外一种是 cgo）\n```\nGODEBUG=netdns=go\n```\n\n具体可参考 commit [fix: bug for docker dns problem](https://github.com/elliotxx/watchman/commit/4f97389897d61ca1a7bafefacd42bbbcb01c052c)\n\nref: \n* [golang中的dns问题](https://blog.csdn.net/wllenyj/article/details/86316629)\n* [fabcar example: fatal error: unexpected signal during runtime execution 'signal SIGSEGV: segmentation violation code=0x1 addr=0x63 pc=0x7f84bc4ea259'](https://stackoverflow.com/questions/55688884/fabcar-example-fatal-error-unexpected-signal-during-runtime-execution-signal)\n\n## 参考资料\n* 程序员笔记——如何编写优雅的Dockerfile  \nhttps://studygolang.com/articles/20102\n\n* Dockerfile语法  \nhttps://blog.csdn.net/u013755520/article/details/91126933\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felliotxx%2Fwatchman","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felliotxx%2Fwatchman","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felliotxx%2Fwatchman/lists"}