-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Golang Toolkits #2
Comments
📦 Package
🤖️ AI IntroGin is an HTTP web framework written in Go (Golang) that features a Martini-like API with performance that is up to 40 times faster, thanks to httprouter. It provides a rich set of functionalities to quickly develop high-performing web applications. It's well-suited for building RESTful APIs with features like middleware support, JSON validation, and rendering, among others. 📝 Examplepackage main
import "github.com/gin-gonic/gin"
func main() {
// Create a new Gin router instance
r := gin.Default()
// Define a simple GET route
r.GET("/ping", func(c *gin.Context) {
// Respond with a JSON object
c.JSON(200, gin.H{
"message": "pong",
})
})
// Start the server on port 8080
r.Run(":8080") // Listen and serve on localhost:8080
} 🧭 Related
🔖 NoteGin is widely regarded as the most renowned web application framework within the Go ecosystem. It was the first web framework I utilized and the one I've used most frequently since I began to learn Go. With its comprehensive ecosystem, outstanding performance, and beginner-friendly approach, it stands out as an excellent choice for developers entering the Go language domain. Additionally, there are several highly recognized web frameworks, including: One should select the most suitable web framework based on individual preferences and practices. HTTP routing in the standard library is now more expressive 🎉.The patterns used by |
📦 Package
🤖️ AI IntroChi is a lightweight routing package for Go, emphasizing simplicity and composability. It builds on the standard 📝 Examplepackage main
import (
"net/http"
"github.com/go-chi/chi/v5"
)
func main() {
router := chi.NewRouter()
// A simple GET route
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Home Page"))
})
// URL parameter route
router.Get("/users/{userID}", func(w http.ResponseWriter, r *http.Request) {
userID := chi.URLParam(r, "userID")
w.Write([]byte("User ID: " + userID))
})
// Start server
http.ListenAndServe(":8080", router)
} 🧭 Related🔖 NoteIn comparison to Gin, Chi provides a more lightweight, closer-to-native Go HTTP routing framework. Furthermore, it offers a more user-friendly routing builder than both Go's native |
📦 Package
🤖️ AI IntroService Weaver is a programming framework designed to simplify the process of creating, deploying, and managing distributed applications. The core of a Service Weaver application is composed of components, which are represented as Go interfaces. These components interact with each other via method calls, removing the need for manual networking or serialization code. Service Weaver offers libraries to assist in logging, metrics, tracing, routing, testing, and more. The deployment of a Service Weaver application is very straightforward, requiring only one command. The system automatically manages the bifurcation of your binary along component boundaries, facilitating the running of different components on different machines. Service Weaver handles replication, autoscaling, and co-location of distributed components, while also managing the networking details, ensuring seamless communication between various components and with clients. 📝 Examplepackage main
import (
"context"
"fmt"
"log"
"github.com/ServiceWeaver/weaver"
)
func main() {
if err := weaver.Run(context.Background(), serve); err != nil {
log.Fatal(err)
}
}
// app is the main component of the application. weaver.Run creates
// it and passes it to serve.
type app struct{
weaver.Implements[weaver.Main]
}
// serve is called by weaver.Run and contains the body of the application.
func serve(context.Context, *app) error {
fmt.Println("Hello")
return nil
} 🧭 Related |
📦 Package
🤖️ AI IntroKratos is a robust Go microservices framework designed to build scalable and maintainable systems. It includes a variety of out-of-the-box features such as service discovery, configuration management, messaging, and resiliency strategies for dealing with failures. It follows the best practices and conventions for microservice architecture, simplifying both the bootstrapping and the development of service-oriented applications. 📝 Example🧭 Related |
📦 Package
🤖️ AI IntroHertz is a Go web framework designed for building microservices with a focus on high performance and extensibility. It simplifies network programming and has built-in support for creating HTTP1.x/HTTP2 servers or clients. Inspired by other popular frameworks such as Echo and Gin, Hertz provides developers with a robust set of tools to develop efficient and safe web services quickly. 📝 Examplepackage main
import (
"context"
"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/cloudwego/hertz/pkg/common/utils"
"github.com/cloudwego/hertz/pkg/protocol/consts"
)
func main() {
h := server.Default()
h.GET("/ping", func(c context.Context, ctx *app.RequestContext) {
ctx.JSON(consts.StatusOK, utils.H{"message": "pong"})
})
h.Spin()
} 🧭 Related |
📦 Package
🤖️ AI IntroKitex is a high-performance and scalable network framework for building efficient communication systems. It is specially designed to handle large volumes of network traffic with minimal overhead. Kitex achieves this through optimizations at the connection, protocol, and application layers. Kitex's functionality includes message routing, load balancing, and fault tolerance among others. It facilitates rapid development of services through the provision of essential tools and libraries that solve common network programming tasks. With Kitex, developers can focus on application logic, rather than having to grapple with low-level network details. In summary, Kitex is a crucial tool that enables developers to build robust and efficient network-based applications, providing a balance of speed, flexibility, and scalability. 📝 Example🧭 Related |
🎯 Tool
🤖️ AI IntroBetteralign is a modification of the official Go fieldalignment tool, designed to identify and optimise memory usage of structs by rearranging their fields. Its functionality is similar to the original, but it introduces several changes. It ignores generated files, skips over test files, and bypasses structs marked with the comment 'betteralign:ignore'. Importantly, this version is able to preserve comments such as field comments and doc comments. Although the comment position heuristics feature is still under development, betteralign provides reliable atomic file I/O, with a promise of not corrupting or losing content on rewrite. It also outperforms its predecessor in testing and is compatible with environments with limited CPU or memory resources, including Docker containers, K8s containers, LXC, LXD, etc. 🏹 Usagemain.go package main
import "unsafe"
type UserName struct {
name string
// ZST [0]func() makes the surrounding type incomparable
_phantom [0]func()
}
func main() {
println(unsafe.Sizeof(UserName{}), unsafe.Sizeof("")) // 24 16
} $ go run main.go
24 16 To get all recommendations on your project: $ betteralign ./...
main.go:5:15: struct of size 24 could be 16 To automatically fix your project files, while ignoring test and generated files: $ betteralign -apply ./...
main.go:5:15: struct of size 24 could be 16 $ go run main.go
16 16
$ cat main.go | grep -A 4 'type UserName struct'
type UserName struct {
// ZST [0]func() makes the surrounding type incomparable
_phantom [0]func()
name string
} 🧭 Related🔖 NoteIn daily programming, struct is frequently used to group fields (that may be of different types) for creating model objects, providing function parameters and return values, and managing data with complex structures. Often, the impact of field sequencing within a struct on memory usage (memory fragmentation) is overlooked. This can be due to a variety of reasons including, but not limited to, demanding a comprehension understanding of the underlying memory model amongst developers, whether the need for extreme performance tailored to the current business context and considering the trade-off between significant effort for trivial memory usage reduction at the current stage. The |
🎯 Tool
🤖️ AI IntroThe 🏹 Usagemain.go package main
import "fmt"
func main() {
var g Greeter
g = Helloer{}
g.Greet()
}
type Greeter interface{ Greet() }
type Helloer struct{}
type Goodbyer struct{}
var _ Greeter = Helloer{} // Helloer implements Greeter
var _ Greeter = Goodbyer{} // Goodbyer implements Greeter
func (Helloer) Greet() { hello() }
func (Goodbyer) Greet() { goodbye() }
func hello() { fmt.Println("hello") }
func goodbye() { fmt.Println("goodbye") } When we execute it, it says hello: $ go run .
hello When we run deadcode on this program, the tool tells us that the goodbye function and the Goodbyer.Greet method are both unreachable: $ deadcode .
greet.go:23: unreachable func: goodbye
greet.go:20: unreachable func: Goodbyer.Greet The tool can also explain why the hello function is live. It responds with a chain of function calls that reaches hello, starting from main: $ deadcode -whylive=example.com/greet.hello .
example.com/greet.main
dynamic@L0008 --> example.com/greet.Helloer.Greet
static@L0019 --> example.com/greet.hello The output is designed to be easy to read on a terminal, but you can use the -json or -f=template flags to specify richer output formats for consumption by other tools. 🧭 Related🔖 NoteThe Go team recently published an article titled 'Finding Unreachable Functions with Deadcode' on their official blog. The article provides detailed examples of using the There are many static check tools in Golang, one of which is golangci-lint, that I currently utilize. It includes a linter called |
📦 Package
🤖️ AI IntroThe 📝 Exampleimport (
"context"
"fmt"
"github.com/redis/go-redis/v9"
)
var ctx = context.Background()
func ExampleClient() {
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
})
err := rdb.Set(ctx, "key", "value", 0).Err()
if err != nil {
panic(err)
}
val, err := rdb.Get(ctx, "key").Result()
if err != nil {
panic(err)
}
fmt.Println("key", val)
val2, err := rdb.Get(ctx, "key2").Result()
if err == redis.Nil {
fmt.Println("key2 does not exist")
} else if err != nil {
panic(err)
} else {
fmt.Println("key2", val2)
}
// Output: key value
// key2 does not exist
} 🧭 Related🔖 Note
|
📦 Package
🤖️ AI Introconc tries to solve common problems in handling concurrency in Go. It provides safer versions of sync.WaitGroup and sync.Pool with error handling and limitations. It also offers utilities for running tasks in an ordered stream and for concurrent mapping and iteration over slices. Moreover, it includes a panics.Catcher feature to gracefully manage panics in goroutines to avoid crashes. 📝 Example// Spawn a set of goroutines and waiting for them to finish
func main() {
var wg conc.WaitGroup
wg.Go(doSomethingThatMightPanic)
// panics with a nice stacktrace
wg.Wait()
}
// Process each element of a stream in a static pool of goroutines
func process(stream chan int) {
p := pool.New().WithMaxGoroutines(10)
for elem := range stream {
elem := elem
p.Go(func() {
handle(elem)
})
}
p.Wait()
}
// Process each element of a slice in a static pool of goroutines
func process(values []int) {
iter.ForEach(values, handle)
}
// Concurrently map a slice
func concMap(
input []int,
f func(*int) int,
) []int {
return iter.Map(input, f)
}
// Process an ordered stream concurrently
func mapStream(
in chan int,
out chan int,
f func(int) int,
) {
s := stream.New().WithMaxGoroutines(10)
for elem := range in {
elem := elem
s.Go(func() stream.Callback {
res := f(elem)
return func() { out <- res }
})
}
s.Wait()
} 🧭 Related |
📦 Package
🤖️ AI IntroThe shopspring/decimal Go package is an arbitrary-precision fixed-point decimal number library. The decimal library can represent numbers with a maximum of 2^31 digits after the decimal point. It supports operations such as addition, subtraction, and multiplication with no loss of precision, and division with specified precision. It also caters to Database/sql serialization/deserialization along with JSON and XML serialization/deserialization. 📝 Examplepackage main
import (
"fmt"
"github.com/shopspring/decimal"
)
func main() {
price, err := decimal.NewFromString("136.02")
if err != nil {
panic(err)
}
quantity := decimal.NewFromInt(3)
fee, _ := decimal.NewFromString(".035")
taxRate, _ := decimal.NewFromString(".08875")
subtotal := price.Mul(quantity)
preTax := subtotal.Mul(fee.Add(decimal.NewFromFloat(1)))
total := preTax.Mul(taxRate.Add(decimal.NewFromFloat(1)))
fmt.Println("Subtotal:", subtotal) // Subtotal: 408.06
fmt.Println("Pre-tax:", preTax) // Pre-tax: 422.3421
fmt.Println("Taxes:", total.Sub(preTax)) // Taxes: 37.482861375
fmt.Println("Total:", total) // Total: 459.824961375
fmt.Println("Tax rate:", total.Sub(preTax).Div(preTax)) // Tax rate: 0.08875
} 🧭 Related |
📦 Package
🤖️ AI IntroThis Go package is a library for scheduling jobs. It's made with simplicity in mind and uses the standard cron syntax. It offers its built-in function-based Job type, but users can supply their own Job implementents as well. 📝 Examplepackage main
import (
"fmt"
"time"
"github.com/robfig/cron/v3"
)
func main() {
c := cron.New(cron.WithSeconds())
c.AddFunc("*/5 * * * * *", func() {
fmt.Println("Every 5 seconds job", time.Now().Format(time.RFC3339))
})
c.Start()
for {
time.Sleep(time.Second)
fmt.Println("Current time", time.Now().Format(time.RFC3339))
}
} 🧭 Related |
📦 Package
🤖️ AI Introzap is a structured, leveled logging library designed with both low-latency applications and the flexibility of structured logging in mind. It includes a reflection-free, zero-allocation JSON encoder, and provides options for level logging and encoding. Built with multi-threaded performance considerations and with a consistent, predictable, and easy-to-use API, it's an excellent option for applications of any size. 📝 Examplepackage main
import (
"go.uber.org/zap"
)
func main() {
logger, _ := zap.NewProduction()
defer logger.Sync() // flushes buffer, if any
sugar := logger.Sugar()
sugar.Infow("failed to fetch URL",
// Structured context as loosely typed key-value pairs.
"url", "http://example.com",
"attempt", 3,
"backoff", time.Second,
)
} 🧭 Related |
📦 Package
🤖️ AI Introgeoip2-golang gives you the ability to use MaxMind GeoIP2 and GeoLite2 databases efficiently and easily. This helps you fetch geographical location data based on IP addresses with high accuracy, such as the city, country, and continent. 📝 Examplepackage main
import (
"fmt"
"log"
"net"
"github.com/oschwald/geoip2-golang"
)
func main() {
db, err := geoip2.Open("GeoIP2-City.mmdb")
if err != nil {
log.Fatal(err)
}
defer db.Close()
// If you are using strings that may be invalid, check that ip is not nil
ip := net.ParseIP("81.2.69.142")
record, err := db.City(ip)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Portuguese (BR) city name: %v\n", record.City.Names["pt-BR"])
if len(record.Subdivisions) > 0 {
fmt.Printf("English subdivision name: %v\n", record.Subdivisions[0].Names["en"])
}
fmt.Printf("Russian country name: %v\n", record.Country.Names["ru"])
fmt.Printf("ISO country code: %v\n", record.Country.IsoCode)
fmt.Printf("Time zone: %v\n", record.Location.TimeZone)
fmt.Printf("Coordinates: %v, %v\n", record.Location.Latitude, record.Location.Longitude)
// Output:
// Portuguese (BR) city name: Londres
// English subdivision name: England
// Russian country name: Великобритания
// ISO country code: GB
// Time zone: Europe/London
// Coordinates: 51.5142, -0.0931
} 🧭 Related |
📦 Package
🤖️ AI Intronow is a Go package that provides a wide array of functionalities to simplify work with time, beyond what's offered by Go's inbuilt time package. It boasts a robust feature set that allows you to parse, format and manipulate time with ease. This package is highly useful to deal with tasks such as getting the start/end of a day/week/month/year, or calculating the duration between two time points. 📝 Exampleimport "github.com/jinzhu/now"
time.Now() // 2013-11-18 17:51:49.123456789 Mon
now.BeginningOfMinute() // 2013-11-18 17:51:00 Mon
now.BeginningOfHour() // 2013-11-18 17:00:00 Mon
now.BeginningOfDay() // 2013-11-18 00:00:00 Mon
now.BeginningOfWeek() // 2013-11-17 00:00:00 Sun
now.BeginningOfMonth() // 2013-11-01 00:00:00 Fri
now.BeginningOfQuarter() // 2013-10-01 00:00:00 Tue
now.BeginningOfYear() // 2013-01-01 00:00:00 Tue
now.EndOfMinute() // 2013-11-18 17:51:59.999999999 Mon
now.EndOfHour() // 2013-11-18 17:59:59.999999999 Mon
now.EndOfDay() // 2013-11-18 23:59:59.999999999 Mon
now.EndOfWeek() // 2013-11-23 23:59:59.999999999 Sat
now.EndOfMonth() // 2013-11-30 23:59:59.999999999 Sat
now.EndOfQuarter() // 2013-12-31 23:59:59.999999999 Tue
now.EndOfYear() // 2013-12-31 23:59:59.999999999 Tue
now.WeekStartDay = time.Monday // Set Monday as first day, default is Sunday
now.EndOfWeek() // 2013-11-24 23:59:59.999999999 Sun 🧭 Related |
📦 Package
🤖️ AI Introcopier offers great utility when dealing with complex data structures in Go. It allows you to duplicate structures, even when dealing with nested fields. This is especially useful when the depth or complexity of the given structure is high or when you need to manage data with many levels of nested fields. 📝 Examplepackage main
import (
"fmt"
"github.com/jinzhu/copier"
)
type User struct {
Name string
Role string
Age int32
EmployeeCode int64 `copier:"EmployeeNum"` // specify field name
// Explicitly ignored in the destination struct.
Salary int
}
func (user *User) DoubleAge() int32 {
return 2 * user.Age
}
// Tags in the destination Struct provide instructions to copier.Copy to ignore
// or enforce copying and to panic or return an error if a field was not copied.
type Employee struct {
// Tell copier.Copy to panic if this field is not copied.
Name string `copier:"must"`
// Tell copier.Copy to return an error if this field is not copied.
Age int32 `copier:"must,nopanic"`
// Tell copier.Copy to explicitly ignore copying this field.
Salary int `copier:"-"`
DoubleAge int32
EmployeeId int64 `copier:"EmployeeNum"` // specify field name
SuperRole string
}
func (employee *Employee) Role(role string) {
employee.SuperRole = "Super " + role
}
func main() {
var (
user = User{Name: "Jinzhu", Age: 18, Role: "Admin", Salary: 200000}
users = []User{{Name: "Jinzhu", Age: 18, Role: "Admin", Salary: 100000}, {Name: "jinzhu 2", Age: 30, Role: "Dev", Salary: 60000}}
employee = Employee{Salary: 150000}
employees = []Employee{}
)
copier.Copy(&employee, &user)
fmt.Printf("%#v \n", employee)
// Employee{
// Name: "Jinzhu", // Copy from field
// Age: 18, // Copy from field
// Salary:150000, // Copying explicitly ignored
// DoubleAge: 36, // Copy from method
// EmployeeId: 0, // Ignored
// SuperRole: "Super Admin", // Copy to method
// }
// Copy struct to slice
copier.Copy(&employees, &user)
fmt.Printf("%#v \n", employees)
// []Employee{
// {Name: "Jinzhu", Age: 18, Salary:0, DoubleAge: 36, EmployeeId: 0, SuperRole: "Super Admin"}
// }
// Copy slice to slice
employees = []Employee{}
copier.Copy(&employees, &users)
fmt.Printf("%#v \n", employees)
// []Employee{
// {Name: "Jinzhu", Age: 18, Salary:0, DoubleAge: 36, EmployeeId: 0, SuperRole: "Super Admin"},
// {Name: "jinzhu 2", Age: 30, Salary:0, DoubleAge: 60, EmployeeId: 0, SuperRole: "Super Dev"},
// }
// Copy map to map
map1 := map[int]int{3: 6, 4: 8}
map2 := map[int32]int8{}
copier.Copy(&map2, map1)
fmt.Printf("%#v \n", map2)
// map[int32]int8{3:6, 4:8}
} 🧭 Related |
🎯 Tool
🤖️ AI Introgo-spew package provides a deep pretty printer for Go data structures to help in debugging. It offers a handy and straightforward approach to dump variables for debugging while doing development. 🏹 UsageThe following is an example usage of package main
import (
"github.com/davecgh/go-spew/spew"
)
type Example struct {
Name string
Age int
}
func main() {
example := &Example{
Name: "Test",
Age: 45,
}
// Using spew to dump the struct
spew.Dump(example)
} This would output something similar to: (*main.Example)(0xc00000c420)({
Name: (string) (len=4) "Test",
Age: (int) 45
}) 🧭 Related🔖 Note |
📦 Package
🤖️ AI Introristretto is a high performance memory-bound Go cache. It is centered around a proactive eviction policy that can outperform traditional LRU algorithms in many scenarios and workloads, which can be beneficial particularly in dealing with large volumes of data. 📝 Examplepackage main
import (
"fmt"
"github.com/dgraph-io/ristretto"
)
func main() {
cache, err := ristretto.NewCache(&ristretto.Config{
NumCounters: 1e7, // number of keys to track frequency of (10M).
MaxCost: 1 << 30, // maximum cost of cache (1GB).
BufferItems: 64, // number of keys per Get buffer.
})
if err != nil {
panic(err)
}
// set a value with a cost of 1
cache.Set("key", "value", 1)
// wait for value to pass through buffers
cache.Wait()
// get value from cache
value, found := cache.Get("key")
if !found {
panic("missing value")
}
fmt.Println(value)
// del value from cache
cache.Del("key")
} 🧭 Related |
📦 Package
🤖️ AI Introredsync is a distributed mutual exclusion lock implementation in Go for Redis. It's based on the Redlock algorithm but has its own improvements for reliability, such as not relying on pub/sub for communication, which makes it a suitable component for distributed systems that require a high degree of synchronization. 📝 Examplepackage main
import (
goredislib "github.com/redis/go-redis/v9"
"github.com/go-redsync/redsync/v4"
"github.com/go-redsync/redsync/v4/redis/goredis/v9"
)
func main() {
// Create a pool with go-redis (or redigo) which is the pool redisync will
// use while communicating with Redis. This can also be any pool that
// implements the `redis.Pool` interface.
client := goredislib.NewClient(&goredislib.Options{
Addr: "localhost:6379",
})
pool := goredis.NewPool(client) // or, pool := redigo.NewPool(...)
// Create an instance of redisync to be used to obtain a mutual exclusion
// lock.
rs := redsync.New(pool)
// Obtain a new mutex by using the same name for all instances wanting the
// same lock.
mutexname := "my-global-mutex"
mutex := rs.NewMutex(mutexname)
// Obtain a lock for our given mutex. After this is successful, no one else
// can obtain the same lock (the same mutex name) until we unlock it.
if err := mutex.Lock(); err != nil {
panic(err)
}
// Do your work that requires the lock.
// Release the lock so other processes or threads can obtain a lock.
if ok, err := mutex.Unlock(); !ok || err != nil {
panic("unlock failed")
}
} 🧭 Related |
📦 Package
🤖️ AI Introgorm is a powerful and easy-to-use Object-Relational Mapping (ORM) library for Go programming language (Golang). It automates database operations, reduces the amount of code to write, and makes your code more manageable. It fully supports struct-tag-based query, hooking before and after operations, combining complex transactions, query embedding, and much more. It facilitates database operation for Golang projects and makes it easier to maintain the complex data handling part of applications. 📝 Examplepackage main
import (
"gorm.io/gorm"
"gorm.io/driver/sqlite"
)
type Product struct {
gorm.Model
Code string
Price uint
}
func main() {
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
// Migrate the schema
db.AutoMigrate(&Product{})
// Create
db.Create(&Product{Code: "D42", Price: 100})
// Read
var product Product
db.First(&product, 1) // find product with integer primary key
db.First(&product, "code = ?", "D42") // find product with code D42
// Update - update product's price to 200
db.Model(&product).Update("Price", 200)
// Update - update multiple fields
db.Model(&product).Updates(Product{Price: 200, Code: "F42"}) // non-zero fields
db.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F42"})
// Delete - delete product
db.Delete(&product, 1)
} 🧭 Related |
📦 Package
🤖️ AI IntroThe official MongoDB driver for Go, it provides comprehensive functionality for working with MongoDB. Core features include sessions, transactions, and linearizable reads. With the MongoDB Go driver, you get a strongly typed, comprehensive API, built by MongoDB for Go developers. 📝 Examplepackage main
import (
"context"
"fmt"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func main() {
// Set client options
clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")
// Connect to MongoDB
client, err := mongo.Connect(context.TODO(), clientOptions)
if err != nil {
log.Fatal(err)
}
// Check the connection
err = client.Ping(context.TODO(), nil)
if err != nil {
log.Fatal(err)
}
fmt.Println("Connected to MongoDB!")
collection := client.Database("test").Collection("trainers")
trainer := bson.M{"id": "1", "name": "Ash", "age": 10, "city": "Pallet Town"}
insertResult, err := collection.InsertOne(context.TODO(), trainer)
if err != nil {
log.Fatal(err)
}
fmt.Println("Inserted a single document: ", insertResult.InsertedID)
} 🧭 Related |
📦 Package
🤖️ AI Introtableflip enables developers to handle process restarts gracefully in Go. This package is vastly used in high-performance systems where it's crucial to maintain existing connections during a program's restart to ensure service continuity. 📝 Exampleupg, _ := tableflip.New(tableflip.Options{})
defer upg.Stop()
go func() {
sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGHUP)
for range sig {
upg.Upgrade()
}
}()
// Listen must be called before Ready
ln, _ := upg.Listen("tcp", "localhost:8080")
defer ln.Close()
go http.Serve(ln, nil)
if err := upg.Ready(); err != nil {
panic(err)
}
<-upg.Exit() 🧭 Related |
📦 Package
🤖️ AI Introasynq is a Go library for queueing tasks and processing them asynchronously with workers. It's backed by Redis and is designed to be scalable yet user-friendly. This package offers a comprehensive set of features for managing distributed tasks, such as guaranteed execution, task scheduling, retries for failed tasks, automatic recovery of tasks in case of a crash, weighted and strict priority queues, task de-duplication, and more. It even supports Redis Cluster for auto-sharding and high availability, as well as integration with Prometheus for metrics collection and visualization. 📝 ExampleFirst, write a package that encapsulates task creation and task handling. package tasks
import (
"context"
"encoding/json"
"fmt"
"log"
"time"
"github.com/hibiken/asynq"
)
// A list of task types.
const (
TypeEmailDelivery = "email:deliver"
TypeImageResize = "image:resize"
)
type EmailDeliveryPayload struct {
UserID int
TemplateID string
}
type ImageResizePayload struct {
SourceURL string
}
//----------------------------------------------
// Write a function NewXXXTask to create a task.
// A task consists of a type and a payload.
//----------------------------------------------
func NewEmailDeliveryTask(userID int, tmplID string) (*asynq.Task, error) {
payload, err := json.Marshal(EmailDeliveryPayload{UserID: userID, TemplateID: tmplID})
if err != nil {
return nil, err
}
return asynq.NewTask(TypeEmailDelivery, payload), nil
}
func NewImageResizeTask(src string) (*asynq.Task, error) {
payload, err := json.Marshal(ImageResizePayload{SourceURL: src})
if err != nil {
return nil, err
}
// task options can be passed to NewTask, which can be overridden at enqueue time.
return asynq.NewTask(TypeImageResize, payload, asynq.MaxRetry(5), asynq.Timeout(20 * time.Minute)), nil
}
//---------------------------------------------------------------
// Write a function HandleXXXTask to handle the input task.
// Note that it satisfies the asynq.HandlerFunc interface.
//
// Handler doesn't need to be a function. You can define a type
// that satisfies asynq.Handler interface. See examples below.
//---------------------------------------------------------------
func HandleEmailDeliveryTask(ctx context.Context, t *asynq.Task) error {
var p EmailDeliveryPayload
if err := json.Unmarshal(t.Payload(), &p); err != nil {
return fmt.Errorf("json.Unmarshal failed: %v: %w", err, asynq.SkipRetry)
}
log.Printf("Sending Email to User: user_id=%d, template_id=%s", p.UserID, p.TemplateID)
// Email delivery code ...
return nil
}
// ImageProcessor implements asynq.Handler interface.
type ImageProcessor struct {
// ... fields for struct
}
func (processor *ImageProcessor) ProcessTask(ctx context.Context, t *asynq.Task) error {
var p ImageResizePayload
if err := json.Unmarshal(t.Payload(), &p); err != nil {
return fmt.Errorf("json.Unmarshal failed: %v: %w", err, asynq.SkipRetry)
}
log.Printf("Resizing image: src=%s", p.SourceURL)
// Image resizing code ...
return nil
}
func NewImageProcessor() *ImageProcessor {
return &ImageProcessor{}
} In your application code, import the above package and use Client to put tasks on queues. package main
import (
"log"
"time"
"github.com/hibiken/asynq"
"your/app/package/tasks"
)
const redisAddr = "127.0.0.1:6379"
func main() {
client := asynq.NewClient(asynq.RedisClientOpt{Addr: redisAddr})
defer client.Close()
// ------------------------------------------------------
// Example 1: Enqueue task to be processed immediately.
// Use (*Client).Enqueue method.
// ------------------------------------------------------
task, err := tasks.NewEmailDeliveryTask(42, "some:template:id")
if err != nil {
log.Fatalf("could not create task: %v", err)
}
info, err := client.Enqueue(task)
if err != nil {
log.Fatalf("could not enqueue task: %v", err)
}
log.Printf("enqueued task: id=%s queue=%s", info.ID, info.Queue)
// ------------------------------------------------------------
// Example 2: Schedule task to be processed in the future.
// Use ProcessIn or ProcessAt option.
// ------------------------------------------------------------
info, err = client.Enqueue(task, asynq.ProcessIn(24*time.Hour))
if err != nil {
log.Fatalf("could not schedule task: %v", err)
}
log.Printf("enqueued task: id=%s queue=%s", info.ID, info.Queue)
// ----------------------------------------------------------------------------
// Example 3: Set other options to tune task processing behavior.
// Options include MaxRetry, Queue, Timeout, Deadline, Unique etc.
// ----------------------------------------------------------------------------
task, err = tasks.NewImageResizeTask("https://example.com/myassets/image.jpg")
if err != nil {
log.Fatalf("could not create task: %v", err)
}
info, err = client.Enqueue(task, asynq.MaxRetry(10), asynq.Timeout(3 * time.Minute))
if err != nil {
log.Fatalf("could not enqueue task: %v", err)
}
log.Printf("enqueued task: id=%s queue=%s", info.ID, info.Queue)
} Next, start a worker server to process these tasks in the background. To start the background workers, use Server and provide your Handler to process the tasks. You can optionally use ServeMux to create a handler, just as you would with net/http Handler. package main
import (
"log"
"github.com/hibiken/asynq"
"your/app/package/tasks"
)
const redisAddr = "127.0.0.1:6379"
func main() {
srv := asynq.NewServer(
asynq.RedisClientOpt{Addr: redisAddr},
asynq.Config{
// Specify how many concurrent workers to use
Concurrency: 10,
// Optionally specify multiple queues with different priority.
Queues: map[string]int{
"critical": 6,
"default": 3,
"low": 1,
},
// See the godoc for other configuration options
},
)
// mux maps a type to a handler
mux := asynq.NewServeMux()
mux.HandleFunc(tasks.TypeEmailDelivery, tasks.HandleEmailDeliveryTask)
mux.Handle(tasks.TypeImageResize, tasks.NewImageProcessor())
// ...register other handlers...
if err := srv.Run(mux); err != nil {
log.Fatalf("could not run server: %v", err)
}
} 🧭 Related |
📦 Package
🤖️ AI IntroThe 📝 Examplepackage main
import (
"github.com/spf13/cast"
)
func main() {
v := cast.ToString("mayonegg") // "mayonegg"
n := cast.ToInt("8") // 8
c := cast.ToBool("true") // true
fmt.Println(v, n, c)
} 🧭 Related |
📖 Abstract
Hi~👋🏼 This is a collection of Go-related packages and tools that I frequently use, may potentially use, and ones that I find intriguing.
🗂️ Packages
frameworks
cache
database
utils
🛠️ Tools
More to come… :)
⏫️ Back to home
The text was updated successfully, but these errors were encountered: