英文:
Setting up a golang API that queries a database every hour to refresh its data
问题
我对golang相对较新,希望能得到一些关于如何构建这个项目的高级提示。我正在尝试构建一个REST API:
- 用户通过POST方法提供一个小的JSON数据
- API将用户的输入数据与作为结构体切片存储的参考数据集进行比较,并计算一个值
- 将该值返回给用户
- 每小时从数据库查询数据,并用另一个结构体切片数据集替换原有的参考数据集。基本上,这会刷新参考数据
- 我希望这个刷新任务是异步的,这样就不会影响用户体验
我正在使用golang的Echo框架(https://echo.labstack.com/)。以下是我在类似golang伪代码中的尝试。你会如何设计这个API以实现每小时异步刷新数据?
为了澄清,我卡在“每小时异步后台查询数据库”的部分。我不确定如何在这种情况下实现。
func main() {
e := echo.New()
e.POST("/", func(something) {
// 这个函数查询数据库并将结果保存为结构体切片的参考数据集
dataset := refreshDB()
// 对输入的JSON数据和参考数据集进行一些计算
result := doCalcs(inputJSON, dataset)
// 准备好返回给用户的响应JSON
responseForUser := prepOutput(result)
return responseForUser
})
}
英文:
I'm relatively new to golang and could use some high-level tips on how to structure this. I'm trying to a build a REST API:
- The user would provide a small JSON payload via POST method
- The API compares the user’s input data against a reference dataset stored as a slice of structs and calculates a value
- This value is returned to the user
- Every hour a database is queried to and replaces the slice of structs dataset with another slice of structs dataset. Basically this refreshes the reference data
- I'd like this refreshing job to be async so it doesn't slow down the user experience
I'm using the golang's Echo framework (https://echo.labstack.com/). Here is my attempt in golang-like pseudocode.
How would you structure this API to refresh the data hourly async?
To clarify, the part Im stuck on is the “query the DB every hour async in the background” bit. Im unsure how to do that in thos scenario.
func main() {
e := echo.New()
e.POST("/", func(something) {
// This func queries the DB and saves reference dataset result as a slice of structs
dataset := refreshDB()
// Does some calculations on input JSON data and reference dataset
result := doCalcs(inputJSON, dataset)
// Prep response in neat JSON
responseForUser := prepOutput(result)
return responseForUser
})
}
答案1
得分: 2
在Go语言中,你可以使用goroutine来处理异步代码,使用ticker来定期执行代码。
package main
import (
"fmt"
"time"
"sync"
)
var rwm sync.RWMutex
var sliceOfStructs []struct{/* ... */}
func main() {
go func() {
tick := time.NewTicker(time.Hour)
for range tick.C {
rwm.Lock()
sliceOfStructs = []struct{}{ /* 使用新数据刷新 */ }
rwm.Unlock()
}
}()
// 启动服务器
}
- 如果
sliceOfStructs
需要在多个包中访问,则需要将其导出并移动到一个非main包中,即可以被导入的包。对于rwm
也是一样。 - 确保任何读取
sliceOfStructs
的代码在读取之前调用rwm.RLock
,在完成后调用rwm.RUnlock
。 - 如果有多个goroutine需要写入
sliceOfStructs
,则应将rwm
从sync.RWMutex
更改为sync.Mutex
。
英文:
For async code in Go you can use a goroutine, to execute the code periodically you can use a ticker.
package main
import (
"fmt"
"time"
"sync"
)
var rwm sync.RWMutex
var sliceOfStructs []struct{/* ... */}
func main() {
go func() {
tick := time.NewTicker(time.Hour)
for range tick.C {
rwm.Lock()
sliceOfStructs = []struct{}{ /* refresh with new data */ }
rwm.Unlock()
}
}()
// start server
}
- If
sliceOfStructs
needs to be accessible across multiple packages then you'll need to export it and move it to a non-main package, i.e. one that can be imported. And do the same forrwm
. - Make sure that any code that reads
sliceOfStructs
invokesrwm.RLock
before reading andrwm.RUnlock
when done. - If you have more than one goroutine that needs to write
sliceOfStructs
then you should changerwm
fromsync.RWMutex
tosync.Mutex
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论