为什么我的两个相同的 systemctl 定时器会产生不同数量的输出?
Why procduces my two identical systemctl timers different amount of outputs?
我有两个 raspberry pi 几乎相同的设置。
在两者上,我都有一个 systemctl 服务和一个每 15 秒 运行 的计时器。
该作业调用一个 go 脚本,该脚本读取系统温度并在我的 mariadb 数据库中创建一个日志条目。数据库 运行ning 在其中一个覆盆子上。因此,两个 go 脚本的唯一区别是数据库的主机名和标识符变量,因此我可以在数据库中看到数据库条目来自哪个数据库。其余相同。
问题是 raspberry1 生成的数据库条目比 raspberry2 多。
当我从一个零条目的新数据库开始时。然后 1 有来自 raspberry1 的大约 120 个条目和来自 raspberrie 2 的大约 70 个条目。错误继续。更多时间后,我得到例如 1000 个条目和 700 个条目。
有谁知道差异可能来自哪里?
也许当两个作业都想同时在 mariadb 中创建一个新条目时?
但我几乎可以肯定这是由 mariadb 以某种方式处理的。
详情如下:
FanLog.service
[Unit]
Description=Lüfter Temperatur Logger Service
After=network.target
[Service]
ExecStart=/root/go/temperatur_logger
WorkingDirectory=/root/go
StandardOutput=append:/var/log/TempLogger.log
StandardError=append:/var/log/TempLogger_error.log
User=root
FanLog.timer
[Unit]
Description=Fanlogger Timer
[Timer]
# OnBootSec=15min
# Wochentage-dd-mm hh:mm:ss
# OnCalendar=*-*-* *:05:00
# OnUnitActiveSec=1min
# OnCalendar=minutely
OnCalendar=*-*-* *:*:0/15
# OnCalendar=*-*-* *:0/0:20
[Install]
WantedBy=timers.target
“systemctl status FanLog.timer”的输出似乎没问题。
我最多可以看到 15 秒缩短到几毫秒,如果我重复,我又可以看到 15 秒。
⚡ root@DeskPi /etc/systemd/system systemctl status FanLog.timer
● FanLog.timer - Fanlogger Timer
Loaded: loaded (/etc/systemd/system/FanLog.timer; enabled; vendor preset: enabled)
Active: active (waiting) since Mon 2021-09-20 06:07:22 CEST; 39min ago
Trigger: Mon 2021-09-20 06:46:45 CEST; 13s left
Sep 20 06:07:22 DeskPi systemd[1]: Stopping Fanlogger Timer.
Sep 20 06:07:22 DeskPi systemd[1]: Started Fanlogger Timer.
temperatur_logger.go
package main
import (
"context"
"database/sql"
"fmt"
"log"
"os"
"os/exec"
"time"
"github.com/stianeikeland/go-rpio"
_ "github.com/go-sql-driver/mysql"
)
const (
username = "TempLogger"
password = "XXXXXXXXXXXXX"
hostname = "192.168.1.20:3306" // Different on other device
dbname = "TempLog"
table = "TempLog"
DeviceName = "OctoPi" // Different on other device
)
var (
// Use mcu pin 24, corresponds to GPIO3 on the pi
pin = rpio.Pin(24)
)
func add(x int, y int) int {
return x + y
}
func get_temp(temperatur string) string {
var outputlaenge int
var aktuelle_temperatur string
// Befehl
cmd := exec.Command("sudo", "/usr/bin/vcgencmd", "measure_temp")
// run command
if output, err := cmd.Output(); err != nil {
fmt.Println("Error", err)
} else {
outputlaenge = len(output)
aktuelle_temperatur = string(output[outputlaenge-7 : outputlaenge-3])
// fmt.Println(string(output[outputlaenge-7 : outputlaenge-3]))
}
return aktuelle_temperatur
}
func dsn(dbName string) string {
return fmt.Sprintf("%s:%s@tcp(%s)/%s", username, password, hostname, dbName)
}
func dbConnection() (*sql.DB, error) {
db, err := sql.Open("mysql", dsn(""))
if err != nil {
log.Printf("Error %s when opening DB\n", err)
return nil, err
}
defer db.Close()
ctx, cancelfunc := context.WithTimeout(context.Background(), 5*time.Second)
defer cancelfunc()
if err != nil {
log.Printf("Error %s when creating DB\n", err)
return nil, err
}
db.Close()
db, err = sql.Open("mysql", dsn(dbname))
if err != nil {
log.Printf("Error %s when opening DB", err)
return nil, err
}
db.SetMaxOpenConns(20)
db.SetMaxIdleConns(20)
db.SetConnMaxLifetime(time.Minute * 5)
ctx, cancelfunc = context.WithTimeout(context.Background(), 5*time.Second)
defer cancelfunc()
err = db.PingContext(ctx)
if err != nil {
log.Printf("Errors %s pinging DB", err)
return nil, err
}
log.Printf("Connected to DB %s successfully\n", dbname)
return db, nil
}
type temperatur_eintrag struct {
DeviceName string
record_date string
temperature string
fan bool
}
func insert(db *sql.DB, p temperatur_eintrag) error {
query := "INSERT INTO " + table + "(device_name, record_date, temperature, fan) VALUES (?, ?, ?, ?)"
ctx, cancelfunc := context.WithTimeout(context.Background(), 5*time.Second)
defer cancelfunc()
stmt, err := db.PrepareContext(ctx, query)
if err != nil {
log.Printf("Error %s when preparing SQL statement", err)
return err
}
defer stmt.Close()
res, err := stmt.ExecContext(ctx, p.DeviceName, p.record_date, p.temperature, p.fan)
if err != nil {
log.Printf("Error %s when inserting row into products table", err)
return err
}
rows, err := res.RowsAffected()
if err != nil {
log.Printf("Error %s when finding rows affected", err)
return err
}
log.Printf("%d log entry created ", rows)
return nil
}
func main() {
currentTime := time.Now()
var tempi string
var myFan bool
db, err := dbConnection()
if err != nil {
log.Printf("Error %s when getting db connection", err)
return
}
defer db.Close()
log.Printf("Successfully connected to database")
// Open and map memory to access gpio, check for errors
if err := rpio.Open(); err != nil {
fmt.Println(err)
os.Exit(1)
}
// Unmap gpio memory when done
defer rpio.Close()
// pin.PullUp()
if pin.Read() == 1 {
fmt.Println("Pin High")
myFan = true
} else {
fmt.Println("Pin Low")
myFan = false
}
p := temperatur_eintrag{
DeviceName: DeviceName,
record_date: currentTime.Format("2006-01-02 15:04:05"),
temperature: get_temp(tempi),
fan: myFan,
}
err = insert(db, p)
if err != nil {
log.Printf("Insert failed with error %s", err)
return
}
}
我找到了解决方案:
这两个选项之一使它起作用:
Persistent=true
AccuracySec=2sec
不确定是哪一个,因为我没有测试更多。
FanLog.timer 现在看起来是这样:
[Unit]
Description=Fanlogger Timer
[Timer]
OnCalendar=*:*:0/10
Persistent=true
AccuracySec=2sec
[Install]
WantedBy=timers.target
我有两个 raspberry pi 几乎相同的设置。 在两者上,我都有一个 systemctl 服务和一个每 15 秒 运行 的计时器。 该作业调用一个 go 脚本,该脚本读取系统温度并在我的 mariadb 数据库中创建一个日志条目。数据库 运行ning 在其中一个覆盆子上。因此,两个 go 脚本的唯一区别是数据库的主机名和标识符变量,因此我可以在数据库中看到数据库条目来自哪个数据库。其余相同。
问题是 raspberry1 生成的数据库条目比 raspberry2 多。 当我从一个零条目的新数据库开始时。然后 1 有来自 raspberry1 的大约 120 个条目和来自 raspberrie 2 的大约 70 个条目。错误继续。更多时间后,我得到例如 1000 个条目和 700 个条目。
有谁知道差异可能来自哪里? 也许当两个作业都想同时在 mariadb 中创建一个新条目时? 但我几乎可以肯定这是由 mariadb 以某种方式处理的。
详情如下:
FanLog.service
[Unit]
Description=Lüfter Temperatur Logger Service
After=network.target
[Service]
ExecStart=/root/go/temperatur_logger
WorkingDirectory=/root/go
StandardOutput=append:/var/log/TempLogger.log
StandardError=append:/var/log/TempLogger_error.log
User=root
FanLog.timer
[Unit]
Description=Fanlogger Timer
[Timer]
# OnBootSec=15min
# Wochentage-dd-mm hh:mm:ss
# OnCalendar=*-*-* *:05:00
# OnUnitActiveSec=1min
# OnCalendar=minutely
OnCalendar=*-*-* *:*:0/15
# OnCalendar=*-*-* *:0/0:20
[Install]
WantedBy=timers.target
“systemctl status FanLog.timer”的输出似乎没问题。 我最多可以看到 15 秒缩短到几毫秒,如果我重复,我又可以看到 15 秒。
⚡ root@DeskPi /etc/systemd/system systemctl status FanLog.timer
● FanLog.timer - Fanlogger Timer
Loaded: loaded (/etc/systemd/system/FanLog.timer; enabled; vendor preset: enabled)
Active: active (waiting) since Mon 2021-09-20 06:07:22 CEST; 39min ago
Trigger: Mon 2021-09-20 06:46:45 CEST; 13s left
Sep 20 06:07:22 DeskPi systemd[1]: Stopping Fanlogger Timer.
Sep 20 06:07:22 DeskPi systemd[1]: Started Fanlogger Timer.
temperatur_logger.go
package main
import (
"context"
"database/sql"
"fmt"
"log"
"os"
"os/exec"
"time"
"github.com/stianeikeland/go-rpio"
_ "github.com/go-sql-driver/mysql"
)
const (
username = "TempLogger"
password = "XXXXXXXXXXXXX"
hostname = "192.168.1.20:3306" // Different on other device
dbname = "TempLog"
table = "TempLog"
DeviceName = "OctoPi" // Different on other device
)
var (
// Use mcu pin 24, corresponds to GPIO3 on the pi
pin = rpio.Pin(24)
)
func add(x int, y int) int {
return x + y
}
func get_temp(temperatur string) string {
var outputlaenge int
var aktuelle_temperatur string
// Befehl
cmd := exec.Command("sudo", "/usr/bin/vcgencmd", "measure_temp")
// run command
if output, err := cmd.Output(); err != nil {
fmt.Println("Error", err)
} else {
outputlaenge = len(output)
aktuelle_temperatur = string(output[outputlaenge-7 : outputlaenge-3])
// fmt.Println(string(output[outputlaenge-7 : outputlaenge-3]))
}
return aktuelle_temperatur
}
func dsn(dbName string) string {
return fmt.Sprintf("%s:%s@tcp(%s)/%s", username, password, hostname, dbName)
}
func dbConnection() (*sql.DB, error) {
db, err := sql.Open("mysql", dsn(""))
if err != nil {
log.Printf("Error %s when opening DB\n", err)
return nil, err
}
defer db.Close()
ctx, cancelfunc := context.WithTimeout(context.Background(), 5*time.Second)
defer cancelfunc()
if err != nil {
log.Printf("Error %s when creating DB\n", err)
return nil, err
}
db.Close()
db, err = sql.Open("mysql", dsn(dbname))
if err != nil {
log.Printf("Error %s when opening DB", err)
return nil, err
}
db.SetMaxOpenConns(20)
db.SetMaxIdleConns(20)
db.SetConnMaxLifetime(time.Minute * 5)
ctx, cancelfunc = context.WithTimeout(context.Background(), 5*time.Second)
defer cancelfunc()
err = db.PingContext(ctx)
if err != nil {
log.Printf("Errors %s pinging DB", err)
return nil, err
}
log.Printf("Connected to DB %s successfully\n", dbname)
return db, nil
}
type temperatur_eintrag struct {
DeviceName string
record_date string
temperature string
fan bool
}
func insert(db *sql.DB, p temperatur_eintrag) error {
query := "INSERT INTO " + table + "(device_name, record_date, temperature, fan) VALUES (?, ?, ?, ?)"
ctx, cancelfunc := context.WithTimeout(context.Background(), 5*time.Second)
defer cancelfunc()
stmt, err := db.PrepareContext(ctx, query)
if err != nil {
log.Printf("Error %s when preparing SQL statement", err)
return err
}
defer stmt.Close()
res, err := stmt.ExecContext(ctx, p.DeviceName, p.record_date, p.temperature, p.fan)
if err != nil {
log.Printf("Error %s when inserting row into products table", err)
return err
}
rows, err := res.RowsAffected()
if err != nil {
log.Printf("Error %s when finding rows affected", err)
return err
}
log.Printf("%d log entry created ", rows)
return nil
}
func main() {
currentTime := time.Now()
var tempi string
var myFan bool
db, err := dbConnection()
if err != nil {
log.Printf("Error %s when getting db connection", err)
return
}
defer db.Close()
log.Printf("Successfully connected to database")
// Open and map memory to access gpio, check for errors
if err := rpio.Open(); err != nil {
fmt.Println(err)
os.Exit(1)
}
// Unmap gpio memory when done
defer rpio.Close()
// pin.PullUp()
if pin.Read() == 1 {
fmt.Println("Pin High")
myFan = true
} else {
fmt.Println("Pin Low")
myFan = false
}
p := temperatur_eintrag{
DeviceName: DeviceName,
record_date: currentTime.Format("2006-01-02 15:04:05"),
temperature: get_temp(tempi),
fan: myFan,
}
err = insert(db, p)
if err != nil {
log.Printf("Insert failed with error %s", err)
return
}
}
我找到了解决方案:
这两个选项之一使它起作用:
Persistent=true
AccuracySec=2sec
不确定是哪一个,因为我没有测试更多。
FanLog.timer 现在看起来是这样:
[Unit]
Description=Fanlogger Timer
[Timer]
OnCalendar=*:*:0/10
Persistent=true
AccuracySec=2sec
[Install]
WantedBy=timers.target