feat: redis pipeline

main
sudo pacman -Syu 2023-03-05 16:10:27 +07:00
parent 99ec8d42c7
commit 2db0ca83fc
2 changed files with 106 additions and 3 deletions

View File

@ -268,7 +268,9 @@ internal
href="https://pkg.go.dev/sync#WaitGroup"
rel="nofollow"
>https://pkg.go.dev/sync#WaitGroup</a
>). Because I always need deal with error.
>). Because I always need deal with error. Be super careful with
<code>egCtx</code>, should use this instead of parent
<code>ctx</code> inside <code>eg.Go</code>.
</p>
<p>Example:</p>
<div class="highlight highlight-source-go">
@ -483,7 +485,7 @@ internal
</ul>
<p>
Also, be careful if config value is empty. You should decide to continue
or stop the service if there is no config.
or stop the service if there is empty config.
</p>
<h3>
<a
@ -506,6 +508,64 @@ internal
<a href="https://github.com/go-gorm/gorm">go-gorm/gorm</a>,
<a href="https://github.com/ent/ent">ent/ent</a> is good.
</p>
<h3>
<a
id="user-content-connect-redis-with-redisgo-redis"
class="anchor"
aria-hidden="true"
href="#connect-redis-with-redisgo-redis"
><span aria-hidden="true" class="octicon octicon-link"></span></a
>Connect Redis with
<a href="https://github.com/redis/go-redis">redis/go-redis</a>
</h3>
<p>
Use
<a
href="https://redis.uptrace.dev/guide/go-redis-pipelines.html"
rel="nofollow"
>Pipelines</a
>
for:
</p>
<ul>
<li>HSET and EXPIRE in 1 command.</li>
<li>Multiple GET in 1 command.</li>
</ul>
<p>
Prefer to use <code>Pipelined</code> instead of <code>Pipeline</code>.
Inside <code>Pipelined</code> return <code>redis.Cmder</code> for each
command.
</p>
<p>Example:</p>
<div class="highlight highlight-source-go">
<pre><span class="pl-k">func</span> (<span class="pl-s1">c</span> <span class="pl-c1">*</span><span class="pl-smi">client</span>) <span class="pl-en">HSetWithExpire</span>(<span class="pl-s1">ctx</span> context.<span class="pl-smi">Context</span>, <span class="pl-s1">key</span> <span class="pl-smi">string</span>, <span class="pl-s1">values</span> []<span class="pl-smi">any</span>, <span class="pl-s1">expired</span> time.<span class="pl-smi">Duration</span>) <span class="pl-smi">error</span> {
<span class="pl-s1">cmds</span> <span class="pl-c1">:=</span> <span class="pl-en">make</span>([]redis.<span class="pl-smi">Cmder</span>, <span class="pl-c1">2</span>)
<span class="pl-k">if</span> <span class="pl-s1">_</span>, <span class="pl-s1">err</span> <span class="pl-c1">:=</span> <span class="pl-s1">c</span>.<span class="pl-en">Pipelined</span>(<span class="pl-s1">ctx</span>, <span class="pl-k">func</span>(<span class="pl-s1">pipe</span> redis.<span class="pl-smi">Pipeliner</span>) <span class="pl-smi">error</span> {
<span class="pl-s1">cmds</span>[<span class="pl-c1">0</span>] <span class="pl-c1">=</span> <span class="pl-s1">pipe</span>.<span class="pl-en">HSet</span>(<span class="pl-s1">ctx</span>, <span class="pl-s1">key</span>, <span class="pl-s1">values</span><span class="pl-c1">...</span>)
<span class="pl-k">if</span> <span class="pl-s1">expired</span> <span class="pl-c1">&gt;</span> <span class="pl-c1">0</span> {
<span class="pl-s1">cmds</span>[<span class="pl-c1">1</span>] <span class="pl-c1">=</span> <span class="pl-s1">pipe</span>.<span class="pl-en">Expire</span>(<span class="pl-s1">ctx</span>, <span class="pl-s1">key</span>, <span class="pl-s1">expired</span>)
}
<span class="pl-k">return</span> <span class="pl-c1">nil</span>
}); <span class="pl-s1">err</span> <span class="pl-c1">!=</span> <span class="pl-c1">nil</span> {
<span class="pl-k">return</span> <span class="pl-s1">err</span>
}
<span class="pl-k">for</span> <span class="pl-s1">_</span>, <span class="pl-s1">cmd</span> <span class="pl-c1">:=</span> <span class="pl-k">range</span> <span class="pl-s1">cmds</span> {
<span class="pl-k">if</span> <span class="pl-s1">cmd</span> <span class="pl-c1">==</span> <span class="pl-c1">nil</span> {
<span class="pl-k">continue</span>
}
<span class="pl-k">if</span> <span class="pl-s1">err</span> <span class="pl-c1">:=</span> <span class="pl-s1">cmd</span>.<span class="pl-en">Err</span>(); <span class="pl-s1">err</span> <span class="pl-c1">!=</span> <span class="pl-c1">nil</span> {
<span class="pl-k">return</span> <span class="pl-s1">err</span>
}
}
<span class="pl-k">return</span> <span class="pl-c1">nil</span>
}</pre>
</div>
<h3>
<a
id="user-content-if-you-want-test-just-use-stretchrtestify"

View File

@ -121,6 +121,7 @@ We can fire them parallel :)
Personally, I prefer `errgroup` to `WaitGroup` (https://pkg.go.dev/sync#WaitGroup).
Because I always need deal with error.
Be super careful with `egCtx`, should use this instead of parent `ctx` inside `eg.Go`.
Example:
@ -222,7 +223,7 @@ Why?
- Put all config in single place for easily tracking
Also, be careful if config value is empty.
You should decide to continue or stop the service if there is no config.
You should decide to continue or stop the service if there is empty config.
### Don't overuse ORM libs, no need to handle another layer above SQL.
@ -236,6 +237,48 @@ For example, it is hard to get primary key after insert/update.
So may be you want to use ORM for those cases.
I hear that [go-gorm/gorm](https://github.com/go-gorm/gorm), [ent/ent](https://github.com/ent/ent) is good.
### Connect Redis with [redis/go-redis](https://github.com/redis/go-redis)
Use [Pipelines](https://redis.uptrace.dev/guide/go-redis-pipelines.html) for:
- HSET and EXPIRE in 1 command.
- Multiple GET in 1 command.
Prefer to use `Pipelined` instead of `Pipeline`.
Inside `Pipelined` return `redis.Cmder` for each command.
Example:
```go
func (c *client) HSetWithExpire(ctx context.Context, key string, values []any, expired time.Duration) error {
cmds := make([]redis.Cmder, 2)
if _, err := c.Pipelined(ctx, func(pipe redis.Pipeliner) error {
cmds[0] = pipe.HSet(ctx, key, values...)
if expired > 0 {
cmds[1] = pipe.Expire(ctx, key, expired)
}
return nil
}); err != nil {
return err
}
for _, cmd := range cmds {
if cmd == nil {
continue
}
if err := cmd.Err(); err != nil {
return err
}
}
return nil
}
```
### If you want test, just use [stretchr/testify](https://github.com/stretchr/testify).
It is easy to write a suite test, thanks to testify.