<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Allens' Blog</title><link>https://allens.tech/</link><description>Recent content from Allens' Blog</description><generator>Hugo</generator><language>en-us</language><managingEditor>allens.leng@gmail.com (Allens)</managingEditor><webMaster>allens.leng@gmail.com (Allens)</webMaster><copyright>All articles on this blog are licensed under the BY-NC-SA license agreement unless otherwise stated. Please indicate the source when reprinting!</copyright><lastBuildDate>Mon, 22 Dec 2025 14:00:00 +0800</lastBuildDate><atom:link href="https://allens.tech/index.xml" rel="self" type="application/rss+xml"/><item><title>自我提升计划 - 目录</title><link>https://allens.tech/post/202512221500/</link><pubDate>Mon, 22 Dec 2025 14:00:00 +0800</pubDate><author>allens.leng@gmail.com (Allens)</author><guid>https://allens.tech/post/202512221500/</guid><description>
<![CDATA[<h1>自我提升计划 - 目录</h1><p>Author: Allens(allens.leng@gmail.com)</p>
        
          <h1 id="简介">
<a class="header-anchor" href="#%e7%ae%80%e4%bb%8b"></a>
简介
</h1><blockquote>
<p>针对自己的实际情况，让 opus 帮我列了个学习计划，后续一一跟进。</p>
</blockquote>
<hr>
<h1 id="后端开发进阶学习计划">
<a class="header-anchor" href="#%e5%90%8e%e7%ab%af%e5%bc%80%e5%8f%91%e8%bf%9b%e9%98%b6%e5%ad%a6%e4%b9%a0%e8%ae%a1%e5%88%92"></a>
后端开发进阶学习计划
</h1><blockquote>
<p>适用对象：Go 应用层熟练，底层原理薄弱的非科班程序员
周期：20周（核心16周 + 云原生4周）
每日投入：工作日 2-3 小时，周末 4-6 小时</p>
</blockquote>
<hr>
<h2 id="目录">
<a class="header-anchor" href="#%e7%9b%ae%e5%bd%95"></a>
目录
</h2><ul>
<li><a href="#%E4%B8%80%E5%AD%A6%E4%B9%A0%E6%96%B9%E6%B3%95%E8%AE%BA">一、学习方法论</a></li>
<li><a href="#%E4%BA%8C%E8%83%BD%E5%8A%9B%E7%8E%B0%E7%8A%B6%E5%88%86%E6%9E%90">二、能力现状分析</a></li>
<li><a href="#%E4%B8%89%E6%80%BB%E4%BD%93%E8%A7%84%E5%88%92">三、总体规划</a></li>
<li><a href="#%E5%9B%9B%E9%98%B6%E6%AE%B5%E4%B8%80%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95--mysql%E7%AC%AC1-4%E5%91%A8">四、阶段一：数据结构与算法 + MySQL（第1-4周）</a></li>
<li><a href="#%E4%BA%94%E9%98%B6%E6%AE%B5%E4%BA%8Credis--%E7%BD%91%E7%BB%9C--kafka%E7%AC%AC5-8%E5%91%A8">五、阶段二：Redis + 网络 + Kafka（第5-8周）</a></li>
<li><a href="#%E5%85%AD%E9%98%B6%E6%AE%B5%E4%B8%89%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F--go%E5%BA%95%E5%B1%82%E7%AC%AC9-12%E5%91%A8">六、阶段三：操作系统 + Go底层（第9-12周）</a></li>
<li><a href="#%E4%B8%83%E9%98%B6%E6%AE%B5%E5%9B%9B%E5%88%86%E5%B8%83%E5%BC%8F--%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1--%E9%9D%A2%E8%AF%95%E5%86%B2%E5%88%BA%E7%AC%AC13-16%E5%91%A8">七、阶段四：分布式 + 系统设计 + 面试冲刺（第13-16周）</a></li>
<li><a href="#%E5%85%AB%E9%98%B6%E6%AE%B5%E4%BA%94%E4%BA%91%E5%8E%9F%E7%94%9F-docker--k8s%E7%AC%AC17-20%E5%91%A8">八、阶段五：云原生 Docker + K8s（第17-20周）</a></li>
<li><a href="#%E4%B9%9D%E5%AD%A6%E4%B9%A0%E8%B5%84%E6%BA%90%E6%B1%87%E6%80%BB">九、学习资源汇总</a></li>
<li><a href="#%E5%8D%81%E9%9D%A2%E8%AF%95%E9%AB%98%E9%A2%91%E9%97%AE%E9%A2%98%E6%B8%85%E5%8D%95">十、面试高频问题清单</a></li>
<li><a href="#%E5%8D%81%E4%B8%80%E6%AF%8F%E6%97%A5%E6%89%A7%E8%A1%8C%E6%A8%A1%E6%9D%BF">十一、每日执行模板</a></li>
</ul>
<hr>
<h2 id="一学习方法论">
<a class="header-anchor" href="#%e4%b8%80%e5%ad%a6%e4%b9%a0%e6%96%b9%e6%b3%95%e8%ae%ba"></a>
一、学习方法论
</h2><h3 id="11-费曼学习法核心方法">
<a class="header-anchor" href="#11-%e8%b4%b9%e6%9b%bc%e5%ad%a6%e4%b9%a0%e6%b3%95%e6%a0%b8%e5%bf%83%e6%96%b9%e6%b3%95"></a>
1.1 费曼学习法（核心方法）
</h3><pre tabindex="0"><code>第1步：学习概念
    ↓
第2步：用简单语言教给别人（或写笔记）
    ↓
第3步：发现卡壳的地方 → 回去重新学
    ↓
第4步：简化、类比，直到能用大白话讲清楚
</code></pre><p><strong>实践方式</strong>：</p>
<ul>
<li>每学完一个知识点，假装讲给不懂技术的人听</li>
<li>写技术笔记（不用发布，写给自己看）</li>
<li>能画图就画图，能举例就举例</li>
</ul>
<h3 id="12-学习金字塔">
<a class="header-anchor" href="#12-%e5%ad%a6%e4%b9%a0%e9%87%91%e5%ad%97%e5%a1%94"></a>
1.2 学习金字塔
</h3><pre tabindex="0"><code>被动学习（效率低）
├── 听讲/看视频      5% 留存率
├── 阅读            10%
└── 看演示          30%

主动学习（效率高）✓
├── 讨论/复述       50%
├── 实践练习        75%  ← 刷题、写代码
└── 教给别人        90%  ← 写博客、讲给同事
</code></pre><h3 id="13-间隔重复法">
<a class="header-anchor" href="#13-%e9%97%b4%e9%9a%94%e9%87%8d%e5%a4%8d%e6%b3%95"></a>
1.3 间隔重复法
</h3><p>对抗遗忘曲线：</p>
        
        <hr><p>Published on 2025-12-22 at <a href='https://allens.tech/'>Allens' Blog</a>, last modified on 2025-12-22</p>]]></description><category>目录</category></item><item><title>我的键盘进化日志 - 分体式键盘（Sofle、Corne）</title><link>https://allens.tech/post/202506233440/</link><pubDate>Thu, 12 Jun 2025 23:40:00 +0800</pubDate><author>allens.leng@gmail.com (Allens)</author><guid>https://allens.tech/post/202506233440/</guid><description>
<![CDATA[<h1>我的键盘进化日志 - 分体式键盘（Sofle、Corne）</h1><p>Author: Allens(allens.leng@gmail.com)</p>
        
          <h1 id="描述">
<a class="header-anchor" href="#%e6%8f%8f%e8%bf%b0"></a>
描述
</h1><p>我头痛传统键盘已经很久了，包含有一堆我用不上的 F 区，数字区，功能键区，以及一直要把两只手挤在一起码字，虽然这么多年已经习惯了，但当你享受过分体式键盘，并且习惯了它，我相信你会爱上它 ❤️。</p>
<h2 id="先看看我的爱宠corne">
<a class="header-anchor" href="#%e5%85%88%e7%9c%8b%e7%9c%8b%e6%88%91%e7%9a%84%e7%88%b1%e5%ae%a0corne"></a>
先看看我的爱宠(Corne)
</h2><p><img src="https://st.agopher.com/blog/2025/06/IMG_001.jpeg" alt=""></p>
<p>其实我之前有买过另外一款键盘，也就是 W-sofle，套件、轴体、键帽都是我自己配的，也就是这款:</p>
<p><img src="https://st.agopher.com/blog/2025/06/iShot_2025-06-13_00.00.33%20%281%29.png" alt=""></p>
<p>但是用久了发现手还是需要相当程度的移动，而且也确实觉得不需要那么多按键，不是不需要那些功能，而是键位确实不需要那么多。</p>
<h2 id="vial-配置">
<a class="header-anchor" href="#vial-%e9%85%8d%e7%bd%ae"></a>
VIAL 配置
</h2><p>这个配置我纠结了很久，也改了很多次，但这个就是目前最适合我的方案了。</p>
<h3 id="第-0-层">
<a class="header-anchor" href="#%e7%ac%ac-0-%e5%b1%82"></a>
第 0 层：
</h3><p><img src="https://st.agopher.com/blog/2025/06/iShot_2025-12-23_14.30.53%20%281%29.png" alt=""></p>
<h3 id="第-1-层">
<a class="header-anchor" href="#%e7%ac%ac-1-%e5%b1%82"></a>
第 1 层：
</h3><p><img src="https://st.agopher.com/blog/2025/06/iShot_2025-12-23_14.36.00%20%281%29.png" alt=""></p>
<blockquote>
<p>宏 0 是截图，宏 1 是浏览器标签向左翻，宏 2 是向右翻。</p>
</blockquote>
<h2 id="背景">
<a class="header-anchor" href="#%e8%83%8c%e6%99%af"></a>
背景
</h2><p>接触分体式键盘的契机其实是在配置 <strong>Neovim</strong> 环境的时候关注了<a href="https://www.youtube.com/@joseanmartinez">Josean Martinez</a>的频道，他在推销他自己的设计的 <strong>Corne</strong> 键盘，不过他那个太贵了，我在某宝买的 <strong>Corne</strong> 一共 289 软妹币，<strong>W-sofle</strong> 当时是刚开始折腾，花了小1000，顺便说一嘴，他推荐的桌面管理软件 Aerospace 和 Opencode 给我提升了很多工作效率。</p>
        
        <hr><p>Published on 2025-06-12 at <a href='https://allens.tech/'>Allens' Blog</a>, last modified on 2025-06-12</p>]]></description><category>外设</category></item><item><title>学习笔记 - 关于多个时区 mysql 查询的个人经验</title><link>https://allens.tech/post/202501151800/</link><pubDate>Wed, 15 Jan 2025 18:00:00 +0800</pubDate><author>allens.leng@gmail.com (Allens)</author><guid>https://allens.tech/post/202501151800/</guid><description>
<![CDATA[<h1>学习笔记 - 关于多个时区 mysql 查询的个人经验</h1><p>Author: Allens(allens.leng@gmail.com)</p>
        
          <h2 id="背景">
<a class="header-anchor" href="#%e8%83%8c%e6%99%af"></a>
背景
</h2><p>由于多个国家时区不同，当按照日期查询时，不同的国家需要查询出对应时区的结果，这里记录下实现过程中遇到的问题。</p>
<h2 id="问题">
<a class="header-anchor" href="#%e9%97%ae%e9%a2%98"></a>
问题
</h2><h3 id="数据库结构">
<a class="header-anchor" href="#%e6%95%b0%e6%8d%ae%e5%ba%93%e7%bb%93%e6%9e%84"></a>
数据库结构
</h3><ul>
<li>关于时间的部分，各人建议不要使用 datetime，原因很简单，这个格式不带时区，在跨时区场景下基本上是一定有问题的，虽然 timestamp 存在 2038 年问题。</li>
</ul>
<h3 id="日期比较">
<a class="header-anchor" href="#%e6%97%a5%e6%9c%9f%e6%af%94%e8%be%83"></a>
日期比较
</h3><p>常用的日期比较一般是这样的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span><span style="color:#66d9ef">SELECT</span> <span style="color:#f92672">*</span> <span style="color:#66d9ef">FROM</span> <span style="color:#f92672">`</span>example_table<span style="color:#f92672">`</span> <span style="color:#66d9ef">WHERE</span> createdAt <span style="color:#f92672">&gt;=</span> <span style="color:#e6db74">&#39;2006-01-02 00:00:00&#39;</span> <span style="color:#66d9ef">AND</span> createdAt <span style="color:#f92672">&lt;=</span> <span style="color:#e6db74">&#39;2006-01-03 00:00:00&#39;</span>;
</span></span></code></pre></div><p>由于数据库会根据当前数据库的时间算日期，只要客户端的当前时区和数据库的时区有差异，那用这个 sql 就一定有问题。</p>
<p>这里提几个点：</p>
<ol>
<li>不能用带时区的字符串来做这件事，类似这样 <code>2024-12-10T17:46:06+08:00</code> 数据库会警告，因为数据库并不能通过这种 format 做到用对应时区来查询。</li>
<li>可以通过函数 <code>UNIX_TIMESTAMP()</code> 来将数据库时间和入参时间都转成 unix 时间戳来做这件事，但不能直接使用。因为如果直接转换，假设数据库是东八区的时区，而入参是 UTC 时区的时间，那么用转换出的值做比较仍然是错的，必须先统一时区，然后在进行时间戳转换，才能保证一致性。</li>
</ol>
<h2 id="方案">
<a class="header-anchor" href="#%e6%96%b9%e6%a1%88"></a>
方案
</h2><p>我的做法是，先获取 go 语言的时间类型（入参是当地时间 0 点的 UTC 时间），加 24 小时作为区间边界，然后再用 sql 做转换比较。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#a6e22e">dateTime</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Parse</span>(<span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">RFC3339</span>, <span style="color:#a6e22e">date</span>)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>, <span style="color:#a6e22e">err</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">err</span> = <span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Table</span>(<span style="color:#e6db74">&#34;example_table&#34;</span>).
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Where</span>(<span style="color:#e6db74">`UNIX_TIMESTAMP(CONVERT_TZ(startedAt, &#39;Asia/Shanghai&#39;, &#39;+00:00&#39;)) &gt;= ?`</span>, <span style="color:#a6e22e">dateTime</span>.<span style="color:#a6e22e">Unix</span>()).
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Where</span>(<span style="color:#e6db74">`UNIX_TIMESTAMP(CONVERT_TZ(startedAt, &#39;Asia/Shanghai&#39;, &#39;+00:00&#39;)) &lt;= ?`</span>, <span style="color:#a6e22e">dateTime</span>.<span style="color:#a6e22e">Add</span>(<span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Hour</span><span style="color:#f92672">*</span><span style="color:#ae81ff">24</span>).<span style="color:#a6e22e">Unix</span>()).
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Order</span>(<span style="color:#e6db74">`startedAt ASC`</span>).<span style="color:#a6e22e">Find</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">docs</span>).<span style="color:#a6e22e">Error</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>, <span style="color:#a6e22e">err</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div>
        
        <hr><p>Published on 2025-01-15 at <a href='https://allens.tech/'>Allens' Blog</a>, last modified on 2025-01-15</p>]]></description><category>学习笔记</category></item><item><title>学习笔记 - gorm + mysql 使用小知识及避坑指南</title><link>https://allens.tech/post/202308082100/</link><pubDate>Tue, 08 Aug 2023 21:00:00 +0800</pubDate><author>allens.leng@gmail.com (Allens)</author><guid>https://allens.tech/post/202308082100/</guid><description>
<![CDATA[<h1>学习笔记 - gorm + mysql 使用小知识及避坑指南</h1><p>Author: Allens(allens.leng@gmail.com)</p>
        
          <h2 id="描述">
<a class="header-anchor" href="#%e6%8f%8f%e8%bf%b0"></a>
描述
</h2><p>作为一个 gorm 的重度使用者，在习惯了 gorm 带来的便利，也遇到了很多的问题，日前看到一些小伙伴仍然会因为对 gorm 特性的不了解，导致出现 panic 或者数据的错误更新的问题，所以这边提供一些小技巧和避坑指南，持续更新&hellip;</p>
<h2 id="插入">
<a class="header-anchor" href="#%e6%8f%92%e5%85%a5"></a>
插入
</h2><h3 id="gorm-解决并发插入报错">
<a class="header-anchor" href="#gorm-%e8%a7%a3%e5%86%b3%e5%b9%b6%e5%8f%91%e6%8f%92%e5%85%a5%e6%8a%a5%e9%94%99"></a>
gorm 解决并发插入报错
</h3><p>当你有并发插入的情况，就难免会出现数据冲突的问题，如果不做处理的话，会出现报错 <code>Duplicate key</code>，gorm 提供了中间件来解决这个问题。</p>
<p>如果你期望 upsert：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#a6e22e">doc</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">model</span>.<span style="color:#a6e22e">Table</span>{<span style="color:#a6e22e">Title</span>: <span style="color:#e6db74">&#34;table&#34;</span>}
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Table</span>(<span style="color:#e6db74">&#34;table&#34;</span>).<span style="color:#a6e22e">Clauses</span>(<span style="color:#a6e22e">clause</span>.<span style="color:#a6e22e">OnConflict</span>{<span style="color:#a6e22e">UpdateAll</span>: <span style="color:#66d9ef">true</span>}).<span style="color:#a6e22e">Create</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">doc</span>).<span style="color:#a6e22e">Error</span>
</span></span></code></pre></div><p>你也可以根据实际使用场景选择其他不同的冲突处理方案：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">OnConflict</span> <span style="color:#66d9ef">struct</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Columns</span>      []<span style="color:#a6e22e">Column</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Where</span>        <span style="color:#a6e22e">Where</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">TargetWhere</span>  <span style="color:#a6e22e">Where</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">OnConstraint</span> <span style="color:#66d9ef">string</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">DoNothing</span>    <span style="color:#66d9ef">bool</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">DoUpdates</span>    <span style="color:#a6e22e">Set</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">UpdateAll</span>    <span style="color:#66d9ef">bool</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h3 id="clauses-on-conflict-do-nothing-带来的问题">
<a class="header-anchor" href="#clauses-on-conflict-do-nothing-%e5%b8%a6%e6%9d%a5%e7%9a%84%e9%97%ae%e9%a2%98"></a>
Clauses on conflict do nothing 带来的问题
</h3><p>如果你和我一样习惯用结构体指针插入，那么如果用 Clauses OnConflict do nothing 解决冲突的同时可能会带来另外一个问题，那就是数据不冲突时，insert id 会回写，但是冲突之后不会进行回写。</p>
<p>部分源码如下：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> !<span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">DryRun</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Error</span> <span style="color:#f92672">==</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">result</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Statement</span>.<span style="color:#a6e22e">ConnPool</span>.<span style="color:#a6e22e">ExecContext</span>(<span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Statement</span>.<span style="color:#a6e22e">Context</span>, <span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Statement</span>.<span style="color:#a6e22e">SQL</span>.<span style="color:#a6e22e">String</span>(), <span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Statement</span>.<span style="color:#a6e22e">Vars</span><span style="color:#f92672">...</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">==</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">RowsAffected</span>, <span style="color:#a6e22e">_</span> = <span style="color:#a6e22e">result</span>.<span style="color:#a6e22e">RowsAffected</span>()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">RowsAffected</span> &gt; <span style="color:#ae81ff">0</span> {
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Statement</span>.<span style="color:#a6e22e">Schema</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Statement</span>.<span style="color:#a6e22e">Schema</span>.<span style="color:#a6e22e">PrioritizedPrimaryField</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Statement</span>.<span style="color:#a6e22e">Schema</span>.<span style="color:#a6e22e">PrioritizedPrimaryField</span>.<span style="color:#a6e22e">HasDefaultValue</span> {
</span></span><span style="display:flex;"><span>				<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">insertID</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">result</span>.<span style="color:#a6e22e">LastInsertId</span>(); <span style="color:#a6e22e">err</span> <span style="color:#f92672">==</span> <span style="color:#66d9ef">nil</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">insertID</span> &gt; <span style="color:#ae81ff">0</span> {
</span></span><span style="display:flex;"><span>					<span style="color:#66d9ef">switch</span> <span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Statement</span>.<span style="color:#a6e22e">ReflectValue</span>.<span style="color:#a6e22e">Kind</span>() {
</span></span><span style="display:flex;"><span>					<span style="color:#66d9ef">case</span> <span style="color:#a6e22e">reflect</span>.<span style="color:#a6e22e">Slice</span>, <span style="color:#a6e22e">reflect</span>.<span style="color:#a6e22e">Array</span>:
</span></span><span style="display:flex;"><span>						<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">config</span>.<span style="color:#a6e22e">LastInsertIDReversed</span> {
</span></span><span style="display:flex;"><span>							<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Statement</span>.<span style="color:#a6e22e">ReflectValue</span>.<span style="color:#a6e22e">Len</span>() <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span>; <span style="color:#a6e22e">i</span> <span style="color:#f92672">&gt;=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span><span style="color:#f92672">--</span> {
</span></span><span style="display:flex;"><span>								<span style="color:#a6e22e">rv</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Statement</span>.<span style="color:#a6e22e">ReflectValue</span>.<span style="color:#a6e22e">Index</span>(<span style="color:#a6e22e">i</span>)
</span></span><span style="display:flex;"><span>								<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">reflect</span>.<span style="color:#a6e22e">Indirect</span>(<span style="color:#a6e22e">rv</span>).<span style="color:#a6e22e">Kind</span>() <span style="color:#f92672">!=</span> <span style="color:#a6e22e">reflect</span>.<span style="color:#a6e22e">Struct</span> {
</span></span><span style="display:flex;"><span>									<span style="color:#66d9ef">break</span>
</span></span><span style="display:flex;"><span>								}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>								<span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">isZero</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Statement</span>.<span style="color:#a6e22e">Schema</span>.<span style="color:#a6e22e">PrioritizedPrimaryField</span>.<span style="color:#a6e22e">ValueOf</span>(<span style="color:#a6e22e">rv</span>)
</span></span><span style="display:flex;"><span>								<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">isZero</span> {
</span></span><span style="display:flex;"><span>									<span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Statement</span>.<span style="color:#a6e22e">Schema</span>.<span style="color:#a6e22e">PrioritizedPrimaryField</span>.<span style="color:#a6e22e">Set</span>(<span style="color:#a6e22e">rv</span>, <span style="color:#a6e22e">insertID</span>)
</span></span><span style="display:flex;"><span>									<span style="color:#a6e22e">insertID</span> <span style="color:#f92672">-=</span> <span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Statement</span>.<span style="color:#a6e22e">Schema</span>.<span style="color:#a6e22e">PrioritizedPrimaryField</span>.<span style="color:#a6e22e">AutoIncrementIncrement</span>
</span></span><span style="display:flex;"><span>								}
</span></span><span style="display:flex;"><span>							}
</span></span><span style="display:flex;"><span>						} <span style="color:#66d9ef">else</span> {
</span></span><span style="display:flex;"><span>							<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> &lt; <span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Statement</span>.<span style="color:#a6e22e">ReflectValue</span>.<span style="color:#a6e22e">Len</span>(); <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span> {
</span></span><span style="display:flex;"><span>								<span style="color:#a6e22e">rv</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Statement</span>.<span style="color:#a6e22e">ReflectValue</span>.<span style="color:#a6e22e">Index</span>(<span style="color:#a6e22e">i</span>)
</span></span><span style="display:flex;"><span>								<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">reflect</span>.<span style="color:#a6e22e">Indirect</span>(<span style="color:#a6e22e">rv</span>).<span style="color:#a6e22e">Kind</span>() <span style="color:#f92672">!=</span> <span style="color:#a6e22e">reflect</span>.<span style="color:#a6e22e">Struct</span> {
</span></span><span style="display:flex;"><span>									<span style="color:#66d9ef">break</span>
</span></span><span style="display:flex;"><span>								}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>								<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">isZero</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Statement</span>.<span style="color:#a6e22e">Schema</span>.<span style="color:#a6e22e">PrioritizedPrimaryField</span>.<span style="color:#a6e22e">ValueOf</span>(<span style="color:#a6e22e">rv</span>); <span style="color:#a6e22e">isZero</span> {
</span></span><span style="display:flex;"><span>									<span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Statement</span>.<span style="color:#a6e22e">Schema</span>.<span style="color:#a6e22e">PrioritizedPrimaryField</span>.<span style="color:#a6e22e">Set</span>(<span style="color:#a6e22e">rv</span>, <span style="color:#a6e22e">insertID</span>)
</span></span><span style="display:flex;"><span>									<span style="color:#a6e22e">insertID</span> <span style="color:#f92672">+=</span> <span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Statement</span>.<span style="color:#a6e22e">Schema</span>.<span style="color:#a6e22e">PrioritizedPrimaryField</span>.<span style="color:#a6e22e">AutoIncrementIncrement</span>
</span></span><span style="display:flex;"><span>								}
</span></span><span style="display:flex;"><span>							}
</span></span><span style="display:flex;"><span>						}
</span></span><span style="display:flex;"><span>					<span style="color:#66d9ef">case</span> <span style="color:#a6e22e">reflect</span>.<span style="color:#a6e22e">Struct</span>:
</span></span><span style="display:flex;"><span>						<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">isZero</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Statement</span>.<span style="color:#a6e22e">Schema</span>.<span style="color:#a6e22e">PrioritizedPrimaryField</span>.<span style="color:#a6e22e">ValueOf</span>(<span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Statement</span>.<span style="color:#a6e22e">ReflectValue</span>); <span style="color:#a6e22e">isZero</span> {
</span></span><span style="display:flex;"><span>							<span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Statement</span>.<span style="color:#a6e22e">Schema</span>.<span style="color:#a6e22e">PrioritizedPrimaryField</span>.<span style="color:#a6e22e">Set</span>(<span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Statement</span>.<span style="color:#a6e22e">ReflectValue</span>, <span style="color:#a6e22e">insertID</span>)
</span></span><span style="display:flex;"><span>						}
</span></span><span style="display:flex;"><span>					}
</span></span><span style="display:flex;"><span>				} <span style="color:#66d9ef">else</span> {
</span></span><span style="display:flex;"><span>					<span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">AddError</span>(<span style="color:#a6e22e">err</span>)
</span></span><span style="display:flex;"><span>				}
</span></span><span style="display:flex;"><span>			}
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>	} <span style="color:#66d9ef">else</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">AddError</span>(<span style="color:#a6e22e">err</span>)
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>大概意思就是，如果影响行数 &gt; 1 才会进行 insert id 赋值，也就是说，如果此时直接使用 doc 中的 id，那么这个 id 的值会是 0。</p>
        
        <hr><p>Published on 2023-08-08 at <a href='https://allens.tech/'>Allens' Blog</a>, last modified on 2023-08-08</p>]]></description><category>学习笔记</category></item><item><title>Cursor - 人工智能编写代码的强大之处</title><link>https://allens.tech/post/202304272007/</link><pubDate>Thu, 27 Apr 2023 20:07:03 +0800</pubDate><author>allens.leng@gmail.com (Allens)</author><guid>https://allens.tech/post/202304272007/</guid><description>
<![CDATA[<h1>Cursor - 人工智能编写代码的强大之处</h1><p>Author: Allens(allens.leng@gmail.com)</p>
        
          <h2 id="描述">
<a class="header-anchor" href="#%e6%8f%8f%e8%bf%b0"></a>
描述
</h2><p>最近需要写一个告警的功能，本来是打算自己实现 metric 和 alert，但是由于我们本来就已经有 grafana 和 prometheus 了，就想要借助成熟体系来实现，这样可以节省很多工作，但是找了一些库，都没有合适的姿势入场，最近主管推给我一个软件 <a href="https://www.cursor.so/">Cursor</a>，来试一下。</p>
<h3 id="使用">
<a class="header-anchor" href="#%e4%bd%bf%e7%94%a8"></a>
使用
</h3><ul>
<li>先来看下主界面
<img src="/img/2023-04-27/1.png" alt=""></li>
<li>command + k
<img src="/img/2023-04-27/2.png" alt=""></li>
<li>来试一下
<img src="/img/2023-04-27/3.png" alt=""></li>
<li>效果
<img src="/img/2023-04-27/4.png" alt=""></li>
<li>很好，但是好像没有鉴权 [ command + a &amp; command + k ]
<img src="/img/2023-04-27/5.png" alt=""></li>
<li>ok，文件太长就不截图了</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Import necessary packages</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> (
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;context&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;crypto/tls&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;fmt&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;net&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;net/http&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;time&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;github.com/prometheus/client_golang/api&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">v1</span> <span style="color:#e6db74">&#34;github.com/prometheus/client_golang/api/prometheus/v1&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;github.com/prometheus/common/model&#34;</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// BasicAuthRoundTripper is a RoundTripper that adds basic authentication credentials to requests</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">BasicAuthRoundTripper</span> <span style="color:#66d9ef">struct</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Username</span>     <span style="color:#66d9ef">string</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Password</span>     <span style="color:#66d9ef">string</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">RoundTripper</span> <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">RoundTripper</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">rt</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">BasicAuthRoundTripper</span>) <span style="color:#a6e22e">RoundTrip</span>(<span style="color:#a6e22e">req</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Request</span>) (<span style="color:#f92672">*</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Response</span>, <span style="color:#66d9ef">error</span>) {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">req</span>.<span style="color:#a6e22e">SetBasicAuth</span>(<span style="color:#a6e22e">rt</span>.<span style="color:#a6e22e">Username</span>, <span style="color:#a6e22e">rt</span>.<span style="color:#a6e22e">Password</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">rt</span>.<span style="color:#a6e22e">RoundTripper</span>.<span style="color:#a6e22e">RoundTrip</span>(<span style="color:#a6e22e">req</span>)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Define a struct to hold the query results</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">QueryResult</span> <span style="color:#66d9ef">struct</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Metric</span> <span style="color:#a6e22e">model</span>.<span style="color:#a6e22e">Metric</span>      <span style="color:#e6db74">`json:&#34;metric&#34;`</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Value</span>  <span style="color:#a6e22e">model</span>.<span style="color:#a6e22e">SampleValue</span> <span style="color:#e6db74">`json:&#34;value&#34;`</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Define a function to query Prometheus with a given username, password</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">QueryPrometheus</span>(<span style="color:#a6e22e">username</span> <span style="color:#66d9ef">string</span>, <span style="color:#a6e22e">password</span> <span style="color:#66d9ef">string</span>, <span style="color:#a6e22e">query</span> <span style="color:#66d9ef">string</span>) ([]<span style="color:#a6e22e">QueryResult</span>, <span style="color:#66d9ef">error</span>) {
</span></span><span style="display:flex;"><span>	<span style="color:#75715e">// Create a new HTTP client with the given username and password</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">client</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">api</span>.<span style="color:#a6e22e">NewClient</span>(<span style="color:#a6e22e">api</span>.<span style="color:#a6e22e">Config</span>{
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">Address</span>: <span style="color:#e6db74">&#34;http://localhost:9090&#34;</span>,
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">RoundTripper</span>: <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">BasicAuthRoundTripper</span>{
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">Username</span>: <span style="color:#a6e22e">username</span>,
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">Password</span>: <span style="color:#a6e22e">password</span>,
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">RoundTripper</span>: <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Transport</span>{
</span></span><span style="display:flex;"><span>				<span style="color:#a6e22e">Proxy</span>:           <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">ProxyFromEnvironment</span>,
</span></span><span style="display:flex;"><span>				<span style="color:#a6e22e">TLSClientConfig</span>: <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">tls</span>.<span style="color:#a6e22e">Config</span>{<span style="color:#a6e22e">InsecureSkipVerify</span>: <span style="color:#66d9ef">true</span>},
</span></span><span style="display:flex;"><span>				<span style="color:#75715e">// Set the username and password for basic authentication</span>
</span></span><span style="display:flex;"><span>				<span style="color:#75715e">// Note: this is not secure and should not be used in production</span>
</span></span><span style="display:flex;"><span>				<span style="color:#75715e">// Instead, use a secure authentication method such as OAuth2</span>
</span></span><span style="display:flex;"><span>				<span style="color:#75715e">// or a reverse proxy with authentication</span>
</span></span><span style="display:flex;"><span>				<span style="color:#a6e22e">DialContext</span>: (<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">net</span>.<span style="color:#a6e22e">Dialer</span>{
</span></span><span style="display:flex;"><span>					<span style="color:#a6e22e">Timeout</span>:   <span style="color:#ae81ff">30</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Second</span>,
</span></span><span style="display:flex;"><span>					<span style="color:#a6e22e">KeepAlive</span>: <span style="color:#ae81ff">30</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Second</span>,
</span></span><span style="display:flex;"><span>				}).<span style="color:#a6e22e">DialContext</span>,
</span></span><span style="display:flex;"><span>				<span style="color:#a6e22e">ForceAttemptHTTP2</span>:     <span style="color:#66d9ef">true</span>,
</span></span><span style="display:flex;"><span>				<span style="color:#a6e22e">MaxIdleConns</span>:          <span style="color:#ae81ff">100</span>,
</span></span><span style="display:flex;"><span>				<span style="color:#a6e22e">IdleConnTimeout</span>:       <span style="color:#ae81ff">90</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Second</span>,
</span></span><span style="display:flex;"><span>				<span style="color:#a6e22e">TLSHandshakeTimeout</span>:   <span style="color:#ae81ff">10</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Second</span>,
</span></span><span style="display:flex;"><span>				<span style="color:#a6e22e">ExpectContinueTimeout</span>: <span style="color:#ae81ff">1</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Second</span>,
</span></span><span style="display:flex;"><span>				<span style="color:#a6e22e">ProxyConnectHeader</span>:    <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Header</span>{},
</span></span><span style="display:flex;"><span>			},
</span></span><span style="display:flex;"><span>		},
</span></span><span style="display:flex;"><span>	})
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>, <span style="color:#a6e22e">err</span>
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#75715e">// Create a new Prometheus API client</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">prometheusClient</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">v1</span>.<span style="color:#a6e22e">NewAPI</span>(<span style="color:#a6e22e">client</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#75715e">// Query Prometheus with the built query string</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">result</span>, <span style="color:#a6e22e">warnings</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">prometheusClient</span>.<span style="color:#a6e22e">Query</span>(<span style="color:#a6e22e">context</span>.<span style="color:#a6e22e">Background</span>(), <span style="color:#a6e22e">query</span>, <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Now</span>())
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>, <span style="color:#a6e22e">err</span>
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> len(<span style="color:#a6e22e">warnings</span>) &gt; <span style="color:#ae81ff">0</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;Warnings:&#34;</span>, <span style="color:#a6e22e">warnings</span>)
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#75715e">// Parse the query result into a slice of QueryResult structs</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">queryResults</span> []<span style="color:#a6e22e">QueryResult</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">res</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">result</span>.(<span style="color:#a6e22e">model</span>.<span style="color:#a6e22e">Vector</span>) {
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">queryResults</span> = append(<span style="color:#a6e22e">queryResults</span>, <span style="color:#a6e22e">QueryResult</span>{
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">Metric</span>: <span style="color:#a6e22e">res</span>.<span style="color:#a6e22e">Metric</span>,
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">Value</span>:  <span style="color:#a6e22e">res</span>.<span style="color:#a6e22e">Value</span>,
</span></span><span style="display:flex;"><span>		})
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">queryResults</span>, <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><ul>
<li>感觉还是不够，如果能按照 label 查询就更好了。
<img src="/img/2023-04-27/6.png" alt=""></li>
<li>结果如下</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Import necessary packages</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> (
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;context&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;crypto/tls&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;fmt&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;net&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;net/http&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;time&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;github.com/prometheus/client_golang/api&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">v1</span> <span style="color:#e6db74">&#34;github.com/prometheus/client_golang/api/prometheus/v1&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;github.com/prometheus/common/model&#34;</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// BasicAuthRoundTripper is a RoundTripper that adds basic authentication credentials to requests</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">BasicAuthRoundTripper</span> <span style="color:#66d9ef">struct</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Username</span>     <span style="color:#66d9ef">string</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Password</span>     <span style="color:#66d9ef">string</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">RoundTripper</span> <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">RoundTripper</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">rt</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">BasicAuthRoundTripper</span>) <span style="color:#a6e22e">RoundTrip</span>(<span style="color:#a6e22e">req</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Request</span>) (<span style="color:#f92672">*</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Response</span>, <span style="color:#66d9ef">error</span>) {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">req</span>.<span style="color:#a6e22e">SetBasicAuth</span>(<span style="color:#a6e22e">rt</span>.<span style="color:#a6e22e">Username</span>, <span style="color:#a6e22e">rt</span>.<span style="color:#a6e22e">Password</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">rt</span>.<span style="color:#a6e22e">RoundTripper</span>.<span style="color:#a6e22e">RoundTrip</span>(<span style="color:#a6e22e">req</span>)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Define a struct to hold the query results</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">QueryResult</span> <span style="color:#66d9ef">struct</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Metric</span> <span style="color:#a6e22e">model</span>.<span style="color:#a6e22e">Metric</span>      <span style="color:#e6db74">`json:&#34;metric&#34;`</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Value</span>  <span style="color:#a6e22e">model</span>.<span style="color:#a6e22e">SampleValue</span> <span style="color:#e6db74">`json:&#34;value&#34;`</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Define a function to query Prometheus with a given username, password, and label</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">QueryPrometheus</span>(<span style="color:#a6e22e">username</span> <span style="color:#66d9ef">string</span>, <span style="color:#a6e22e">password</span> <span style="color:#66d9ef">string</span>, <span style="color:#a6e22e">my_metric</span> <span style="color:#66d9ef">string</span>, <span style="color:#a6e22e">key</span> <span style="color:#66d9ef">string</span>, <span style="color:#a6e22e">value</span> <span style="color:#66d9ef">string</span>) ([]<span style="color:#a6e22e">QueryResult</span>, <span style="color:#66d9ef">error</span>) {
</span></span><span style="display:flex;"><span>	<span style="color:#75715e">// Create a new HTTP client with the given username and password</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">client</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">api</span>.<span style="color:#a6e22e">NewClient</span>(<span style="color:#a6e22e">api</span>.<span style="color:#a6e22e">Config</span>{
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">Address</span>: <span style="color:#e6db74">&#34;http://localhost:9090&#34;</span>,
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">RoundTripper</span>: <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">BasicAuthRoundTripper</span>{
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">Username</span>: <span style="color:#a6e22e">username</span>,
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">Password</span>: <span style="color:#a6e22e">password</span>,
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">RoundTripper</span>: <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Transport</span>{
</span></span><span style="display:flex;"><span>				<span style="color:#a6e22e">Proxy</span>:           <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">ProxyFromEnvironment</span>,
</span></span><span style="display:flex;"><span>				<span style="color:#a6e22e">TLSClientConfig</span>: <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">tls</span>.<span style="color:#a6e22e">Config</span>{<span style="color:#a6e22e">InsecureSkipVerify</span>: <span style="color:#66d9ef">true</span>},
</span></span><span style="display:flex;"><span>				<span style="color:#75715e">// Set the username and password for basic authentication</span>
</span></span><span style="display:flex;"><span>				<span style="color:#75715e">// Note: this is not secure and should not be used in production</span>
</span></span><span style="display:flex;"><span>				<span style="color:#75715e">// Instead, use a secure authentication method such as OAuth2</span>
</span></span><span style="display:flex;"><span>				<span style="color:#75715e">// or a reverse proxy with authentication</span>
</span></span><span style="display:flex;"><span>				<span style="color:#a6e22e">DialContext</span>: (<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">net</span>.<span style="color:#a6e22e">Dialer</span>{
</span></span><span style="display:flex;"><span>					<span style="color:#a6e22e">Timeout</span>:   <span style="color:#ae81ff">30</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Second</span>,
</span></span><span style="display:flex;"><span>					<span style="color:#a6e22e">KeepAlive</span>: <span style="color:#ae81ff">30</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Second</span>,
</span></span><span style="display:flex;"><span>				}).<span style="color:#a6e22e">DialContext</span>,
</span></span><span style="display:flex;"><span>				<span style="color:#a6e22e">ForceAttemptHTTP2</span>:     <span style="color:#66d9ef">true</span>,
</span></span><span style="display:flex;"><span>				<span style="color:#a6e22e">MaxIdleConns</span>:          <span style="color:#ae81ff">100</span>,
</span></span><span style="display:flex;"><span>				<span style="color:#a6e22e">IdleConnTimeout</span>:       <span style="color:#ae81ff">90</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Second</span>,
</span></span><span style="display:flex;"><span>				<span style="color:#a6e22e">TLSHandshakeTimeout</span>:   <span style="color:#ae81ff">10</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Second</span>,
</span></span><span style="display:flex;"><span>				<span style="color:#a6e22e">ExpectContinueTimeout</span>: <span style="color:#ae81ff">1</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Second</span>,
</span></span><span style="display:flex;"><span>				<span style="color:#a6e22e">ProxyConnectHeader</span>:    <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Header</span>{},
</span></span><span style="display:flex;"><span>			},
</span></span><span style="display:flex;"><span>		},
</span></span><span style="display:flex;"><span>	})
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>, <span style="color:#a6e22e">err</span>
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#75715e">// Create a new Prometheus API client</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">prometheusClient</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">v1</span>.<span style="color:#a6e22e">NewAPI</span>(<span style="color:#a6e22e">client</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#75715e">// Build the query string with the given label</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">query</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Sprintf</span>(<span style="color:#e6db74">`%s{%s=&#34;%s&#34;}`</span>, <span style="color:#a6e22e">my_metric</span>, <span style="color:#a6e22e">key</span>, <span style="color:#a6e22e">value</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#75715e">// Query Prometheus with the built query string</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">result</span>, <span style="color:#a6e22e">warnings</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">prometheusClient</span>.<span style="color:#a6e22e">Query</span>(<span style="color:#a6e22e">context</span>.<span style="color:#a6e22e">Background</span>(), <span style="color:#a6e22e">query</span>, <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Now</span>())
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>, <span style="color:#a6e22e">err</span>
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> len(<span style="color:#a6e22e">warnings</span>) &gt; <span style="color:#ae81ff">0</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;Warnings:&#34;</span>, <span style="color:#a6e22e">warnings</span>)
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#75715e">// Parse the query result into a slice of QueryResult structs</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">queryResults</span> []<span style="color:#a6e22e">QueryResult</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">res</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">result</span>.(<span style="color:#a6e22e">model</span>.<span style="color:#a6e22e">Vector</span>) {
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">queryResults</span> = append(<span style="color:#a6e22e">queryResults</span>, <span style="color:#a6e22e">QueryResult</span>{
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">Metric</span>: <span style="color:#a6e22e">res</span>.<span style="color:#a6e22e">Metric</span>,
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">Value</span>:  <span style="color:#a6e22e">res</span>.<span style="color:#a6e22e">Value</span>,
</span></span><span style="display:flex;"><span>		})
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">queryResults</span>, <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>很好，感觉自己要失业了。</p>
        
        <hr><p>Published on 2023-04-27 at <a href='https://allens.tech/'>Allens' Blog</a>, last modified on 2023-04-27</p>]]></description><category>AI</category></item><item><title>学习笔记 - 并发编程 ☞ errgroup</title><link>https://allens.tech/post/202304262059/</link><pubDate>Wed, 26 Apr 2023 20:59:19 +0800</pubDate><author>allens.leng@gmail.com (Allens)</author><guid>https://allens.tech/post/202304262059/</guid><description>
<![CDATA[<h1>学习笔记 - 并发编程 ☞ errgroup</h1><p>Author: Allens(allens.leng@gmail.com)</p>
        
          <h2 id="描述">
<a class="header-anchor" href="#%e6%8f%8f%e8%bf%b0"></a>
描述
</h2><p>Go 的优势无非在于并发编程，当你需要对数组中每一个元素都组装一个信息的时候，就涉及到并发处理的问题，毕竟根据组装数据的复杂程度，处理时间会指数型上涨，下面通过 sync.WaitGroup 和 errgroup.Group 两中方式分别对这种情况进行了处理。</p>
<h3 id="syncwaitgroup-demo">
<a class="header-anchor" href="#syncwaitgroup-demo"></a>
sync.WaitGroup demo
</h3><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> (
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;context&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;encoding/json&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;sync&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;testing&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;github.com/stretchr/testify/assert&#34;</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Class</span> <span style="color:#66d9ef">struct</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Id</span>      <span style="color:#66d9ef">int64</span>      <span style="color:#e6db74">`json:&#34;id&#34;`</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Name</span>    <span style="color:#66d9ef">string</span>     <span style="color:#e6db74">`json:&#34;name&#34;`</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Grade</span>   <span style="color:#66d9ef">string</span>     <span style="color:#e6db74">`json:&#34;grade&#34;`</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Student</span> []<span style="color:#f92672">*</span><span style="color:#a6e22e">Student</span> <span style="color:#e6db74">`json:&#34;student&#34;`</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Student</span> <span style="color:#66d9ef">struct</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Id</span>      <span style="color:#66d9ef">int64</span>  <span style="color:#e6db74">`json:&#34;id&#34;`</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">ClassId</span> <span style="color:#66d9ef">int64</span>  <span style="color:#e6db74">`json:&#34;classId&#34;`</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Name</span>    <span style="color:#66d9ef">string</span> <span style="color:#e6db74">`json:&#34;name&#34;`</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">TestWaitGroup</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) {
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">var</span> (
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">mu</span>       <span style="color:#a6e22e">sync</span>.<span style="color:#a6e22e">Mutex</span>
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">wg</span>       = <span style="color:#a6e22e">sync</span>.<span style="color:#a6e22e">WaitGroup</span>{}
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">errs</span>     = make([]<span style="color:#66d9ef">error</span>, <span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">classArr</span> = []<span style="color:#f92672">*</span><span style="color:#a6e22e">Class</span>{{<span style="color:#a6e22e">Id</span>: <span style="color:#ae81ff">1</span>}, {<span style="color:#a6e22e">Id</span>: <span style="color:#ae81ff">2</span>}, {<span style="color:#a6e22e">Id</span>: <span style="color:#ae81ff">3</span>}}
</span></span><span style="display:flex;"><span>	)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">wg</span>.<span style="color:#a6e22e">Add</span>(len(<span style="color:#a6e22e">classArr</span>))
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">item</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">classArr</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">go</span> <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">class</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">Class</span>) {
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">defer</span> <span style="color:#a6e22e">wg</span>.<span style="color:#a6e22e">Done</span>()
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">ctx</span>, <span style="color:#a6e22e">cancel</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">context</span>.<span style="color:#a6e22e">WithTimeout</span>(<span style="color:#a6e22e">context</span>.<span style="color:#a6e22e">Background</span>(), <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Second</span><span style="color:#f92672">*</span><span style="color:#ae81ff">5</span>)
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">defer</span> <span style="color:#a6e22e">cancel</span>()
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">students</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">queryAllStudent</span>(<span style="color:#a6e22e">ctx</span>, <span style="color:#a6e22e">class</span>.<span style="color:#a6e22e">Id</span>)
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>				<span style="color:#a6e22e">mu</span>.<span style="color:#a6e22e">Lock</span>()
</span></span><span style="display:flex;"><span>				<span style="color:#a6e22e">errs</span> = append(<span style="color:#a6e22e">errs</span>, <span style="color:#a6e22e">err</span>)
</span></span><span style="display:flex;"><span>				<span style="color:#a6e22e">mu</span>.<span style="color:#a6e22e">Unlock</span>()
</span></span><span style="display:flex;"><span>				<span style="color:#66d9ef">return</span>
</span></span><span style="display:flex;"><span>			}
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">class</span>.<span style="color:#a6e22e">Student</span> = <span style="color:#a6e22e">students</span>
</span></span><span style="display:flex;"><span>		}(<span style="color:#a6e22e">item</span>)
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">wg</span>.<span style="color:#a6e22e">Wait</span>()
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">assert</span>.<span style="color:#a6e22e">Equal</span>(<span style="color:#a6e22e">t</span>, len(<span style="color:#a6e22e">errs</span>), <span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">bytes</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">json</span>.<span style="color:#a6e22e">Marshal</span>(<span style="color:#a6e22e">classArr</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">assert</span>.<span style="color:#a6e22e">Nil</span>(<span style="color:#a6e22e">t</span>, <span style="color:#a6e22e">err</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Log</span>(string(<span style="color:#a6e22e">bytes</span>))
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">queryAllStudent</span>(<span style="color:#a6e22e">ctx</span> <span style="color:#a6e22e">context</span>.<span style="color:#a6e22e">Context</span>, <span style="color:#a6e22e">classId</span> <span style="color:#66d9ef">int64</span>) ([]<span style="color:#f92672">*</span><span style="color:#a6e22e">Student</span>, <span style="color:#66d9ef">error</span>) {
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">map</span>[<span style="color:#66d9ef">int64</span>][]<span style="color:#f92672">*</span><span style="color:#a6e22e">Student</span>{
</span></span><span style="display:flex;"><span>		<span style="color:#ae81ff">1</span>: []<span style="color:#f92672">*</span><span style="color:#a6e22e">Student</span>{{<span style="color:#a6e22e">Id</span>: <span style="color:#ae81ff">1</span>}, {<span style="color:#a6e22e">Id</span>: <span style="color:#ae81ff">2</span>}, {<span style="color:#a6e22e">Id</span>: <span style="color:#ae81ff">3</span>}},
</span></span><span style="display:flex;"><span>		<span style="color:#ae81ff">2</span>: []<span style="color:#f92672">*</span><span style="color:#a6e22e">Student</span>{{<span style="color:#a6e22e">Id</span>: <span style="color:#ae81ff">4</span>}, {<span style="color:#a6e22e">Id</span>: <span style="color:#ae81ff">5</span>}, {<span style="color:#a6e22e">Id</span>: <span style="color:#ae81ff">6</span>}},
</span></span><span style="display:flex;"><span>		<span style="color:#ae81ff">3</span>: []<span style="color:#f92672">*</span><span style="color:#a6e22e">Student</span>{{<span style="color:#a6e22e">Id</span>: <span style="color:#ae81ff">7</span>}, {<span style="color:#a6e22e">Id</span>: <span style="color:#ae81ff">8</span>}, {<span style="color:#a6e22e">Id</span>: <span style="color:#ae81ff">9</span>}},
</span></span><span style="display:flex;"><span>	}[<span style="color:#a6e22e">classId</span>], <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>我之前都是这么写的，但是这样就会有一个问题，就是 err 的捕获比较难搞，要声明一个 errs ，且返回 err 的时候取 errs 的哪一个元素都感觉不是很合理。</p>
        
        <hr><p>Published on 2023-04-26 at <a href='https://allens.tech/'>Allens' Blog</a>, last modified on 2023-04-26</p>]]></description><category>学习笔记</category></item><item><title>打造 Windows 下的开发环境</title><link>https://allens.tech/post/202202251800/</link><pubDate>Fri, 25 Feb 2022 18:00:00 +0800</pubDate><author>allens.leng@gmail.com (Allens)</author><guid>https://allens.tech/post/202202251800/</guid><description>
<![CDATA[<h1>打造 Windows 下的开发环境</h1><p>Author: Allens(allens.leng@gmail.com)</p>
        
          <h2 id="描述">
<a class="header-anchor" href="#%e6%8f%8f%e8%bf%b0"></a>
描述
</h2><p>说实话已经习惯了用 ** MAC OS ** 进行开发，但是家里目前并没有 <strong>MAC OS</strong>，也确实没有必要为了在家办公买一台，所以就搞起了开发环境，之前也用过 <strong>WSL</strong>，<strong>Arch Linux</strong>,说实话真的不好用，<strong>Arch Linux</strong> 双系统不方便，而且 <strong>VPN</strong> 处处是坑，<strong>WSL</strong>
就更差了，所以最终还是用了 <strong>Windows</strong> 本身进行开发。</p>
<h2 id="命令行工具-windows-terminal">
<a class="header-anchor" href="#%e5%91%bd%e4%bb%a4%e8%a1%8c%e5%b7%a5%e5%85%b7-windows-terminal"></a>
命令行工具 <strong>Windows Terminal</strong>
</h2><p>我是重度命令行使用者，参考了很多文章，觉得 <strong>Windows Terminal</strong> 还是普遍得到认可的，<strong>Windows</strong> 商店直接搜索安装就可以了。
<img src="/img/2022-02-25/1.jpg" alt=""></p>
<h2 id="包管理工具-scoop">
<a class="header-anchor" href="#%e5%8c%85%e7%ae%a1%e7%90%86%e5%b7%a5%e5%85%b7-scoop"></a>
包管理工具 <strong>Scoop</strong>
</h2><p>由于我从来不喜欢系统以外的东西占用<strong>C盘</strong>，所以我把 <strong>scoop</strong> 装在了 <strong>D盘</strong>。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e"># 设置环境变量</span>
</span></span><span style="display:flex;"><span>$env:SCOOP<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;D:\Applications\Scoop&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">[</span>environment<span style="color:#f92672">]</span>::setEnvironmentVariable<span style="color:#f92672">(</span><span style="color:#e6db74">&#39;SCOOP&#39;</span>,<span style="color:#e6db74">&#39;D:\Applications\Scoop&#39;</span>,<span style="color:#e6db74">&#39;User&#39;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 安装 scoop</span>
</span></span><span style="display:flex;"><span>iwr -useb get.scoop.sh | iex
</span></span></code></pre></div><p>安装一些开发工具</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e"># vim</span>
</span></span><span style="display:flex;"><span>scoop install vim
</span></span></code></pre></div><h2 id="安装-node">
<a class="header-anchor" href="#%e5%ae%89%e8%a3%85-node"></a>
安装 Node
</h2><ul>
<li>安装 nvm</li>
</ul>
<blockquote>
<p>安装 nvm 会遇到 Windows 下缺少基础库的问题</p>
</blockquote>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e"># 查看一下都有哪些基础库</span>
</span></span><span style="display:flex;"><span>scoop bucket known
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 我第一个是 main 添加 main</span>
</span></span><span style="display:flex;"><span>scoop bucket add main
</span></span><span style="display:flex;"><span><span style="color:#75715e"># node 版本管理</span>
</span></span><span style="display:flex;"><span>scoop install nvm
</span></span></code></pre></div><h2 id="命令行主题">
<a class="header-anchor" href="#%e5%91%bd%e4%bb%a4%e8%a1%8c%e4%b8%bb%e9%a2%98"></a>
命令行主题
</h2><p>我是一个颜控，所以要安装一个主题，找来找去感觉 <strong>oh-my-posh</strong> 比较适合我，当然用什么风格的可以自己看，通过如下方式可以挑选：</p>
        
        <hr><p>Published on 2022-02-25 at <a href='https://allens.tech/'>Allens' Blog</a>, last modified on 2022-02-25</p>]]></description><category>操作系统</category></item><item><title>学习笔记 - Gopher China</title><link>https://allens.tech/post/202012032000/</link><pubDate>Thu, 03 Dec 2020 20:00:00 +0800</pubDate><author>allens.leng@gmail.com (Allens)</author><guid>https://allens.tech/post/202012032000/</guid><description>
<![CDATA[<h1>学习笔记 - Gopher China</h1><p>Author: Allens(allens.leng@gmail.com)</p>
        
          <h2 id="描述">
<a class="header-anchor" href="#%e6%8f%8f%e8%bf%b0"></a>
描述
</h2><p>参加 Gopher China 2020 感觉所获颇丰，简单整理一下，共勉 …</p>
<h2 id="代码解耦">
<a class="header-anchor" href="#%e4%bb%a3%e7%a0%81%e8%a7%a3%e8%80%a6"></a>
代码解耦
</h2><ul>
<li>旧代码</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Go" data-lang="Go"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> len(<span style="color:#a6e22e">req</span>.<span style="color:#a6e22e">FirstName</span>) <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">msg</span>.<span style="color:#a6e22e">Code</span> = <span style="color:#a6e22e">ErrFirstNameIsRequired</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> len(<span style="color:#a6e22e">req</span>.<span style="color:#a6e22e">LastName</span>) <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">msg</span>.<span style="color:#a6e22e">Code</span> = <span style="color:#a6e22e">ErrLastNameIsRequired</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> len(<span style="color:#a6e22e">req</span>.<span style="color:#a6e22e">Address</span>) <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">msg</span>.<span style="color:#a6e22e">Code</span> = <span style="color:#a6e22e">ErrAddressIsRequired</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> len(<span style="color:#a6e22e">req</span>.<span style="color:#a6e22e">PostalCode</span>) <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">msg</span>.<span style="color:#a6e22e">Code</span> = <span style="color:#a6e22e">ErrPostalCodeIsRequired</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> len(<span style="color:#a6e22e">req</span>.<span style="color:#a6e22e">City</span>) <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">msg</span>.<span style="color:#a6e22e">Code</span> = <span style="color:#a6e22e">ErrCityIsRequired</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><ul>
<li>改动后</li>
</ul>
<blockquote>
<p>抽象一个方法</p>
</blockquote>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Go" data-lang="Go"><span style="display:flex;"><span><span style="color:#75715e">// ValidateString 字符串验证结构</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">ValidateString</span> <span style="color:#66d9ef">struct</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">Str</span>  <span style="color:#66d9ef">string</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">Code</span> <span style="color:#66d9ef">int</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// ValidateEmptyString 验证字符串是否为空</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">ValidateEmptyString</span>(<span style="color:#a6e22e">s</span> []<span style="color:#f92672">*</span><span style="color:#a6e22e">ValidateString</span>) (<span style="color:#a6e22e">code</span> <span style="color:#66d9ef">int</span>, <span style="color:#a6e22e">empty</span> <span style="color:#66d9ef">bool</span>) {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">v</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">s</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> len(<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Str</span>) <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span> {
</span></span><span style="display:flex;"><span>            <span style="color:#a6e22e">empty</span> = <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>            <span style="color:#a6e22e">code</span> = <span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Code</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">return</span>
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><blockquote>
<p>核心逻辑</p>
        
        <hr><p>Published on 2020-12-03 at <a href='https://allens.tech/'>Allens' Blog</a>, last modified on 2020-12-03</p>]]></description><category>学习笔记</category></item><item><title>服务器资源监控</title><link>https://allens.tech/post/202011122000/</link><pubDate>Thu, 12 Nov 2020 20:00:00 +0800</pubDate><author>allens.leng@gmail.com (Allens)</author><guid>https://allens.tech/post/202011122000/</guid><description>
<![CDATA[<h1>服务器资源监控</h1><p>Author: Allens(allens.leng@gmail.com)</p>
        
          <h2 id="描述">
<a class="header-anchor" href="#%e6%8f%8f%e8%bf%b0"></a>
描述
</h2><p>最近手里很多服务器都出现了内存满了或者硬盘满了导致服务器宕机等问题，迫使资源监控成为我的必备技能之一。</p>
<h2 id="站点访问监控">
<a class="header-anchor" href="#%e7%ab%99%e7%82%b9%e8%ae%bf%e9%97%ae%e7%9b%91%e6%8e%a7"></a>
站点访问监控
</h2><p>我一直用的是 MySSL 企业版的网站监控，网站无法访问时，邮件 + 微信提醒还是挺好用的，当然如果不嫌麻烦的话，自己写一个脚本也是可以的。
<img src="/img/2020-11-12/1.jpeg" alt=""></p>
<h2 id="服务器内部资源监控">
<a class="header-anchor" href="#%e6%9c%8d%e5%8a%a1%e5%99%a8%e5%86%85%e9%83%a8%e8%b5%84%e6%ba%90%e7%9b%91%e6%8e%a7"></a>
服务器内部资源监控
</h2><p>这边自己写了个脚本监控网站硬盘资源发送到钉钉，其中钉钉的部分是从 <a href="https://github.com/Berry961103">Berry</a> 那里直接拿来用的。</p>
<ul>
<li>go build 一个 diskMonitor</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Go" data-lang="Go"><span style="display:flex;"><span><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> (
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;bytes&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;encoding/json&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;errors&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;fmt&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;io/ioutil&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;net/http&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;time&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;github.com/shirou/gopsutil/disk&#34;</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// SendGroupType .</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">SendGroupType</span> <span style="color:#66d9ef">struct</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">MsgType</span> <span style="color:#66d9ef">string</span>   <span style="color:#e6db74">`json:&#34;msgtype&#34;`</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Text</span>    <span style="color:#a6e22e">TextType</span> <span style="color:#e6db74">`json:&#34;text&#34;`</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">At</span>      <span style="color:#a6e22e">AtType</span>   <span style="color:#e6db74">`json:&#34;at&#34;`</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">IsAtAll</span> <span style="color:#66d9ef">bool</span>     <span style="color:#e6db74">`json:&#34;isAtAll&#34;`</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// TextType .</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">TextType</span> <span style="color:#66d9ef">struct</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">Content</span> <span style="color:#66d9ef">string</span> <span style="color:#e6db74">`json:&#34;content&#34;`</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// AtType .</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">AtType</span> <span style="color:#66d9ef">struct</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">AtMobiles</span> []<span style="color:#66d9ef">string</span> <span style="color:#e6db74">`json:&#34;atMobiles&#34;`</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// SendGroupResp .</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">SendGroupResp</span> <span style="color:#66d9ef">struct</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">ErrMsg</span>  <span style="color:#66d9ef">string</span> <span style="color:#e6db74">`json:&#34;errmsg&#34;`</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">ErrCode</span> <span style="color:#66d9ef">int</span>    <span style="color:#e6db74">`json:&#34;errcode&#34;`</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> (
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">token</span>       = <span style="color:#e6db74">&#34;your token&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">allensPhone</span> = <span style="color:#e6db74">&#34;your dingtalk phone&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">b</span> = <span style="color:#ae81ff">1024</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">k</span> = <span style="color:#a6e22e">b</span> <span style="color:#f92672">*</span> <span style="color:#ae81ff">1024</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">g</span> = <span style="color:#a6e22e">k</span> <span style="color:#f92672">*</span> <span style="color:#ae81ff">1024</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">diskInfo</span>, <span style="color:#a6e22e">_</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">disk</span>.<span style="color:#a6e22e">Usage</span>(<span style="color:#e6db74">&#34;/&#34;</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">diskInfo</span>.<span style="color:#a6e22e">Free</span><span style="color:#f92672">/</span><span style="color:#a6e22e">g</span> <span style="color:#f92672">&lt;=</span> <span style="color:#ae81ff">3</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">SendDingRobot</span>(<span style="color:#e6db74">&#34;告警： 当前您的服务器 [ XXX ] 硬盘内存剩余已不足 3 G&#34;</span>, []<span style="color:#66d9ef">string</span>{
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">allensPhone</span>,
</span></span><span style="display:flex;"><span>		})
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// SendDingRobot Send text messages to ding robot</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">SendDingRobot</span>(<span style="color:#a6e22e">msg</span> <span style="color:#66d9ef">string</span>, <span style="color:#a6e22e">phone</span> []<span style="color:#66d9ef">string</span>) <span style="color:#66d9ef">error</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">t</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">TextType</span>{
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">Content</span>: <span style="color:#a6e22e">msg</span>,
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">a</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">AtType</span>{
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">AtMobiles</span>: <span style="color:#a6e22e">phone</span>,
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">g</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">SendGroupType</span>{
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">MsgType</span>: <span style="color:#e6db74">&#34;text&#34;</span>,
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">Text</span>:    <span style="color:#a6e22e">t</span>,
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">At</span>:      <span style="color:#a6e22e">a</span>,
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">IsAtAll</span>: <span style="color:#66d9ef">true</span>,
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">sendGroup</span>(<span style="color:#a6e22e">g</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Errorf</span>(<span style="color:#e6db74">&#34;send ding Group err:[%s]&#34;</span>, <span style="color:#a6e22e">err</span>.<span style="color:#a6e22e">Error</span>())
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// SendGroup 发送消息到钉钉群机器人</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">sendGroup</span>(<span style="color:#a6e22e">sendGroup</span> <span style="color:#a6e22e">SendGroupType</span>) <span style="color:#66d9ef">error</span> {
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">client</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Client</span>{
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">Timeout</span>: <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Duration</span>(<span style="color:#ae81ff">15</span>) <span style="color:#f92672">*</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Second</span>,
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">reqData</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">json</span>.<span style="color:#a6e22e">Marshal</span>(<span style="color:#a6e22e">sendGroup</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">err</span>
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">reader</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">bytes</span>.<span style="color:#a6e22e">NewReader</span>(<span style="color:#a6e22e">reqData</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">resp</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">client</span>.<span style="color:#a6e22e">Post</span>(<span style="color:#e6db74">&#34;https://oapi.dingtalk.com/robot/send?access_token=&#34;</span><span style="color:#f92672">+</span><span style="color:#a6e22e">token</span>, <span style="color:#e6db74">&#34;application/json;charset=UTF-8&#34;</span>, <span style="color:#a6e22e">reader</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">err</span>
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">defer</span> <span style="color:#a6e22e">resp</span>.<span style="color:#a6e22e">Body</span>.<span style="color:#a6e22e">Close</span>()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">data</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">ioutil</span>.<span style="color:#a6e22e">ReadAll</span>(<span style="color:#a6e22e">resp</span>.<span style="color:#a6e22e">Body</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">err</span>
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">respData</span> <span style="color:#a6e22e">SendGroupResp</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">err</span> = <span style="color:#a6e22e">json</span>.<span style="color:#a6e22e">Unmarshal</span>(<span style="color:#a6e22e">data</span>, <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">respData</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">err</span>
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">respData</span>.<span style="color:#a6e22e">ErrCode</span> <span style="color:#f92672">!=</span> <span style="color:#ae81ff">0</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">errors</span>.<span style="color:#a6e22e">New</span>(<span style="color:#a6e22e">respData</span>.<span style="color:#a6e22e">ErrMsg</span>)
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><ul>
<li><code>SCP</code> 上传脚本到服务器上</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>scp diskMonitor myservice:~/monitor/disk
</span></span></code></pre></div><ul>
<li>Linux 定时任务</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>crontab -e
</span></span></code></pre></div><blockquote>
<p>后续参数</p>
        
        <hr><p>Published on 2020-11-12 at <a href='https://allens.tech/'>Allens' Blog</a>, last modified on 2020-11-12</p>]]></description><category>服务器</category></item><item><title>个人服务器的那点事</title><link>https://allens.tech/post/202009252024/</link><pubDate>Fri, 25 Sep 2020 20:00:00 +0800</pubDate><author>allens.leng@gmail.com (Allens)</author><guid>https://allens.tech/post/202009252024/</guid><description>
<![CDATA[<h1>个人服务器的那点事</h1><p>Author: Allens(allens.leng@gmail.com)</p>
        
          <h2 id="描述">
<a class="header-anchor" href="#%e6%8f%8f%e8%bf%b0"></a>
描述
</h2><p>私人服务器部署方案以及维护期间的一些心得</p>
<h2 id="访问加速">
<a class="header-anchor" href="#%e8%ae%bf%e9%97%ae%e5%8a%a0%e9%80%9f"></a>
访问加速
</h2><ul>
<li>图片格式：图片尽量选用 JPG 格式，PNG 格式的图片普遍要比 JPG 格式的图片大很多。</li>
<li>图片压缩：过大的资源加载会非常耗时，影响网站渲染的速度，用 <a href="https://tinypng.com/">tinypng</a> 或者 <a href="https://compressjpeg.com/zh/">compress</a> 压缩，清晰度损失很小。</li>
<li>CDN 加速：七牛云的收费性价比很高，可以使用七牛云的对象存储配合 CDN 加速。</li>
</ul>
<h2 id="网站部署">
<a class="header-anchor" href="#%e7%bd%91%e7%ab%99%e9%83%a8%e7%bd%b2"></a>
网站部署
</h2><p>结论先行：我的方案是本地先用 Hugo 生成好静态文件，将静态文件打包到镜像内，然后用 Go 写一个简单的阻塞，编译成二进制文件作为容器启动命令，然后打包成镜像推送到阿里云镜像仓库，然后在服务器用 docker compose 启动一个 Nginx ，通过共享卷的方式访问博客静态页面。</p>
<h3 id="为什么这么做">
<a class="header-anchor" href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e8%bf%99%e4%b9%88%e5%81%9a"></a>
为什么这么做？
</h3><p><strong>为什么本地生成静态文件？</strong></p>
<ol>
<li>国内网络问题镜像下载缓慢</li>
<li>容器内生成，需要 Go 和 Hugo ，Go 依赖下载缓慢</li>
<li>带 Go 和 Hugo 的镜像太大</li>
</ol>
<p><strong>为什么不把博客打包成 Nginx？</strong></p>
<ol>
<li>本身希望服务器上的 Nginx 只是作为 Gateway，不要跟博客打包在一起，也正是这个原因用到了共享卷，为了让 Nginx 容器能访问到博客静态文件，共享卷有缓存问题，记得每次启动的时候清下卷。</li>
<li>希望服务器上只有一个 Nginx，其他的 Pod 只做基础服务。</li>
</ol>
<p><strong>为什么需要构建 Go 的二进制执行文件？</strong></p>
<ul>
<li>Docker 规定 Pod 容器要能提供服务，纯静态文件没有命令是无法启动的，所以我用了个小技巧，写了个 Go 的阻塞当做启动命令。</li>
</ul>
<h3 id="部署文件">
<a class="header-anchor" href="#%e9%83%a8%e7%bd%b2%e6%96%87%e4%bb%b6"></a>
部署文件
</h3><p><strong>dockerfile</strong></p>
        
        <hr><p>Published on 2020-09-25 at <a href='https://allens.tech/'>Allens' Blog</a>, last modified on 2020-09-25</p>]]></description><category>服务器</category></item></channel></rss>