Что может быть лучше для реализации процедуры, которая проверяет и выполняет сообщения в социальных сетях?
Я пишу небольшое приложение для автоматического размещения сообщений в социальных сетях.
Мое намерение состоит в том, чтобы пользователь мог через веб-интерфейс создать сообщение в определенное время, а бот может проверять наличие новых сообщений и выполнять их.
У меня проблемы с работой с рутинами и каналами на 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")
}
}
1 ответ
С ответом Питера я смог адаптировать все потребности, чтобы составить эскиз.
Я не знаю, будет ли это лучшим способом сделать это, может быть, какая-то функция будет излишне потреблять ресурсы обработки. Если у кого-то есть лучшие идеи по рефакторингу, я буду очень рад услышать.
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)")
}
}