Open23

ISUCON Snippets

myuonmyuon

sqlx関連

myuonmyuon
func sqlxIn[P any](resp any, query string, args []P) error {
	if len(args) == 0 {
		return nil
	}

	query, params, err := sqlx.In(query, args)
	if err != nil {
		return err
	}

	return db.Select(resp, query, params...)
}
myuonmyuon

Bulk INSERT

if len(userPresents) > 0 {
    query := `INSERT INTO user_presents(id, user_id, sent_at, item_type, item_id, amount, present_message, created_at, updated_at)
	   VALUES (:id, :user_id, :sent_at, :item_type, :item_id, :amount, :present_message, :created_at, :updated_at)`
    if _, err := tx.NamedExec(query, userPresents); err != nil {
    	return nil, err
    }
}
myuonmyuon

Bulk IODKUの例

if len(insertUserItems) > 0 {
		query := `INSERT INTO user_items(id, user_id, item_id, item_type, amount, created_at, updated_at)
		VALUES (:id, :user_id, :item_id, :item_type, :amount, :created_at, :updated_at)
		ON DUPLICATE KEY UPDATE amount=VALUES(amount), updated_at=VALUES(updated_at)`
		if _, err := tx.NamedExec(query, insertUserItems); err != nil {
			return err
		}
}
myuonmyuon

Go GlobalCache

myuonmyuon
type GlobalCache[K comparable, V any] struct {
	value map[K]V
	*sync.Mutex
}

func NewGlobalCache[K comparable, V any]() *GlobalCache[K, V] {
	return &GlobalCache[K, V]{
		value: make(map[K]V),
		Mutex: &sync.Mutex{},
	}
}

func (c *GlobalCache[K, V]) Load(key K) (V, bool) {
	c.Lock()
	defer c.Unlock()

	v, ok := c.value[key]
	return v, ok
}

func (c *GlobalCache[K, V]) Store(key K, value V) {
	c.Lock()
	defer c.Unlock()

	c.value[key] = value
}

func (c *GlobalCache[K, V]) Delete(key K) {
	c.Lock()
	defer c.Unlock()

	delete(c.value, key)
}

func (c *GlobalCache[K, V]) Clear() {
	c.Lock()
	defer c.Unlock()

	c.value = make(map[K]V)
}

func (c *GlobalCache[K, V]) Keys() []K {
	c.Lock()
	defer c.Unlock()

	keys := make([]K, 0, len(c.value))
	for k := range c.value {
		keys = append(keys, k)
	}
	return keys
}

var (
	bannedUsers = NewGlobalCache[int64, bool]()
)
myuonmyuon

Makefile

myuonmyuon

upload-mysql:
	sudo cp ./conf/mysql.cnf /etc/mysql/mysql.conf.d/

restart-mysql:
	sudo systemctl restart mysql

deploy-mysql: upload-mysql restart-mysql truncate-mysql-log

upload-nginx:
	sudo cp ./conf/nginx.conf /etc/nginx/

restart-nginx:
	sudo systemctl reload nginx

deploy-nginx: upload-nginx restart-nginx truncate-nginx-log

build-go:
	cd webapp/golang && \
	go build -o app

restart-go:
	sudo systemctl restart isu-go

deploy-go: build-go restart-go truncate-go-log

deploy: deploy-mysql deploy-nginx deploy-go

collect-nginx-log:
	sudo cat /var/log/nginx/access.log | ~/go/bin/kataribe > "logs/nginx-$(shell date +'%Y%m%d%H%M%S').log"
	sudo cat /var/log/nginx/error.log > "logs/nginx-error.log"

collect-mysql-log:
	sudo pt-query-digest /var/log/mysql/mysql-slow.log > "logs/mysql-$(shell date +'%Y%m%d%H%M%S').log"

collect-go-log:
	sudo journalctl -u isu-go > "logs/go-app.log"

logs: collect-nginx-log collect-mysql-log collect-go-log

truncate-nginx-log:
	sudo truncate -s 0 /var/log/nginx/access.log
	sudo truncate -s 0 /var/log/nginx/error.log

truncate-mysql-log:
	sudo truncate -s 0 /var/log/mysql/mysql-slow.log

truncate-go-log:
	sudo journalctl --vacuum-time=1s