go - 有什么更好的方法来实现在社交网络中验证和执行帖子的例程?
问题描述
我正在编写一个小型应用程序来在社交网络上执行自动发布。
我的意图是用户可以通过网络界面在特定时间创建帖子,机器人可以检查安排的新帖子并执行它们。
我在 Go 上处理例程和频道时遇到问题。
我将在下面留下一个反映我的代码实际情况的示例。它包含一些注释以使其更易于理解。
实施随时检查新帖子的例程的最佳方法是什么? 记住:
- 用户可以随时输入新帖子。
- 该机器人可以同时管理数百/数千个帐户。尽可能少地消耗处理是必不可少的。
package main
import (
"fmt"
"sync"
"time"
)
var botRunning = true
var wg = &sync.WaitGroup{}
func main() {
// I start the routine of checking for and posting scheduled appointments.
wg.Add(1)
go postingScheduled()
// Later the user passes the command to stop the post.
// At that moment I would like to stop the routine immediately without getting stuck in a loop.
// What is the best way to do this?
time.Sleep(3 * time.Second)
botRunning = false
// ignore down
time.Sleep(2 * time.Second)
panic("")
wg.Wait()
}
// Function that keeps checking whether the routine should continue or not.
// Check every 2 seconds.
// I think this is very wrong because it consumes unnecessary resources.
// -> Is there another way to do this?
func checkRunning() {
for {
fmt.Println("Pause/Running? - ", botRunning)
if botRunning {
break
}
time.Sleep(2 * time.Second)
}
}
// Routine that looks for the scheduled posts in the database.
// It inserts the date of the posts in the Ticker and when the time comes the posting takes place.
// This application will have hundreds of social network accounts and each will have its own function running in parallel.
// -> What better way to check constantly if there are scheduled items in the database consuming the least resources on the machine?
// -> Another important question. User can schedule posts to the database at any time. How do I check for new posts schedule while the Ticker is waiting for the time the last posting loaded?
func postingScheduled() {
fmt.Println("Init bot posting routine")
defer wg.Done()
for {
checkRunning()
<-time.NewTicker(2 * time.Second).C
fmt.Println("posted success")
}
}
解决方案
有了彼得的回应,我能够适应所有需要来制作草图。
我不知道这是否是最好的方法,也许某些功能会不必要地消耗处理资源。如果有人对重构有更好的想法,我将非常感激。
package main
import (
"fmt"
"log"
"net/http"
"sort"
"time"
)
type posting struct {
caption string
scheduledTo time.Time
}
const dateLayoutFormat = "02-01-2006 15:04:05"
var botStatus = true
var indexPosting int
var tickerSchedule = time.NewTicker(1)
var posts = []posting{
{caption: "item 1", scheduledTo: time.Now().Add(5 * time.Second)},
{caption: "item 2", scheduledTo: time.Now().Add(25 * time.Second)},
}
func init() {
indexPosting = len(posts)
}
func main() {
http.HandleFunc("/", func (w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Bem vindo ao bot")
})
http.HandleFunc("/stop", func (w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Parando o bot!")
stopBot()
})
http.HandleFunc("/start", func (w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Iniciando o bot!")
startBot()
})
http.HandleFunc("/add", func (w http.ResponseWriter, r *http.Request) {
t := time.Now().Add(5 * time.Second)
indexPosting++
addItemDB(posting{
caption: fmt.Sprint("item ", indexPosting),
scheduledTo: t,
})
fmt.Fprint(w, "Adicionando nova postagem \nPróximo post será: ", t.Format(dateLayoutFormat))
})
if botStatus {
go workerScheduled()
}
log.Print("Inicnando server...")
if err := http.ListenAndServe(":9090", nil); err != nil {
log.Print("erro ao iniciar servidor => ", err)
}
}
func workerScheduled() {
for {
log.Print("listando as próximas postagens")
pts := getNextPostsDB()
if len(pts) == 0 {
log.Print("sem postagem agendada")
botStatus = false
return
}
p1 := pts[0]
log.Printf("Próxima postagem será: %s \n\n", string(p1.scheduledTo.Format(dateLayoutFormat)))
<- updateTimer(p1.scheduledTo).C
if !botStatus {
log.Print("postagem cancelado, bot status = parado")
return
}
if time.Until(p1.scheduledTo) > 1 * time.Second {
updateTimer(p1.scheduledTo)
log.Print("timer resetado")
continue
}
post(p1)
if len(pts) > 1 {
p2 := pts[1]
updateTimer(p2.scheduledTo)
}
updatePostedDB()
}
}
func updateTimer(t time.Time) *time.Ticker {
tickerSchedule = time.NewTicker(t.Sub(time.Now()))
return tickerSchedule
}
func post(p posting) {
log.Printf("'%s' postado com sucesso", p.caption)
}
func addItemDB(p posting) {
posts = append(posts, p)
if botStatus {
next := getNextPostDB()
updateTimer(next.scheduledTo)
} else {
botStatus = true
go workerScheduled()
}
}
func getNextPostDB() posting {
return getNextPostsDB()[0]
}
func getNextPostsDB() []posting {
orderPostsList()
removePostExpired()
return posts
}
func removePostExpired() {
for _, p := range posts {
if p.scheduledTo.Before(time.Now()) {
log.Printf("removendo postagem expirada")
removePostByIndex(getIndexOf(p))
}
}
}
func removePostByIndex(i int) {
copy(posts[i:], posts[i+1:])
posts = posts[:len(posts)-1]
}
func getIndexOf(post posting) int {
for i, p := range posts {
if p.caption == post.caption {
return i
}
}
return -1
}
func updatePostedDB() {
removePostByIndex(0)
}
func orderPostsList() {
sort.Slice(posts, func(i, j int) bool {
return posts[i].scheduledTo.Before(posts[j].scheduledTo)
})
}
func startBot() {
if !botStatus {
log.Printf("comando 'iniciar bot'")
botStatus = true
go workerScheduled()
} else {
log.Printf("comando 'iniciar bot' (já iniciado)")
}
}
func stopBot() {
if botStatus {
log.Printf("comando 'pausar bot'")
botStatus = false
tickerSchedule.Stop()
} else {
log.Printf("comando 'pausar bot' (já pausado)")
}
}
推荐阅读
- python - Sqlite3 数据库在不应该添加条目时添加了条目
- c++ - C++ 中类成员的动态分配
- python - 将值添加到上下文以在 Django 中呈现
- python - 如何构造属性在某个范围内的 Python pandas 系列对象
- java - 如何将对象转换为仅在运行时已知的类型?
- c# - 第二次点击后页面是否刷新?
- mysql - 如何使用 MySQL 子查询和 GROUP BY
- android - Delphi 通过 AIDL 连接打印服务
- ruby-on-rails - 查找数组的每个子数组包含的值
- python-3.x - 将输入字符串分成两个偶数部分或长度为奇数时,将中间字符留在第一部分。(仅布尔值)