{"id":17289893,"url":"https://github.com/songzhibin97/gkit","last_synced_at":"2025-05-15T09:00:19.378Z","repository":{"id":45709532,"uuid":"324712335","full_name":"songzhibin97/gkit","owner":"songzhibin97","description":"A collection of basic usability component tools dedicated to providing micro-services and single services, drawing on some excellent open source project features such as kratos, go-kit, mosn, sentinel, gopkg core components. I hope you will use and mention issue and pr more often.","archived":false,"fork":false,"pushed_at":"2025-01-19T06:27:06.000Z","size":906,"stargazers_count":328,"open_issues_count":0,"forks_count":43,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-14T14:59:44.907Z","etag":null,"topics":["go","golang","infrastructure","microservice"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/songzhibin97.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-12-27T07:46:46.000Z","updated_at":"2025-04-10T02:42:09.000Z","dependencies_parsed_at":"2024-03-02T03:26:33.947Z","dependency_job_id":"6512f248-20c2-4bcc-a7b2-ce83107e2e20","html_url":"https://github.com/songzhibin97/gkit","commit_stats":{"total_commits":340,"total_committers":5,"mean_commits":68.0,"dds":"0.020588235294117685","last_synced_commit":"e21669d8785dc81597184afb03779bcb58a06050"},"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/songzhibin97%2Fgkit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/songzhibin97%2Fgkit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/songzhibin97%2Fgkit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/songzhibin97%2Fgkit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/songzhibin97","download_url":"https://codeload.github.com/songzhibin97/gkit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254310509,"owners_count":22049467,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","golang","infrastructure","microservice"],"created_at":"2024-10-15T10:36:25.763Z","updated_at":"2025-05-15T09:00:19.331Z","avatar_url":"https://github.com/songzhibin97.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GKIT\n\n```\n_____/\\\\\\\\\\\\\\\\\\\\\\\\__/\\\\\\________/\\\\\\__/\\\\\\\\\\\\\\\\\\\\\\__/\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\_        \n ___/\\\\\\//////////__\\/\\\\\\_____/\\\\\\//__\\/////\\\\\\///__\\///////\\\\\\/////__       \n  __/\\\\\\_____________\\/\\\\\\__/\\\\\\//_________\\/\\\\\\___________\\/\\\\\\_______      \n   _\\/\\\\\\____/\\\\\\\\\\\\\\_\\/\\\\\\\\\\\\//\\\\\\_________\\/\\\\\\___________\\/\\\\\\_______     \n    _\\/\\\\\\___\\/////\\\\\\_\\/\\\\\\//_\\//\\\\\\________\\/\\\\\\___________\\/\\\\\\_______    \n     _\\/\\\\\\_______\\/\\\\\\_\\/\\\\\\____\\//\\\\\\_______\\/\\\\\\___________\\/\\\\\\_______   \n      _\\/\\\\\\_______\\/\\\\\\_\\/\\\\\\_____\\//\\\\\\______\\/\\\\\\___________\\/\\\\\\_______  \n       _\\//\\\\\\\\\\\\\\\\\\\\\\\\/__\\/\\\\\\______\\//\\\\\\__/\\\\\\\\\\\\\\\\\\\\\\_______\\/\\\\\\_______ \n        __\\////////////____\\///________\\///__\\///////////________\\///________                                 \n```\n \n##### Translate to: [简体中文](README_zh.md)\n\n# Project Description\nDedicated to providing microservices and monolithic services of the availability of a collection of basic component tools, drawing on some of the best open source projects such as : `kratos`, `go-kit`, `mosn`, `sentinel`, `gopkg` ... We hope you will support us!\n\n# Directory structure\n```shell\n├── cache (builds cache-related components)\n  ├── buffer (provides byte array reuse and io buffer wrapping)\n  ├── mbuffer (buffer-like implementation) \n  ├── local_cache (provides local key-value wrapper implementation for building local caches)\n  ├── singleflight (provides prevention of duplicate tasks in high concurrency situations, generally used to fill cache miss scenarios)\n├── coding (provides object serialization/deserialization interface, provides json, proto, xml, yaml instance methods)\n├── concurrent (best practices for using channels in concurrency)\n  ├── fan_in (fan-in pattern, commonly used with multiple producers and one consumer in the producer-consumer model)\n  ├── fan_out (fan-out mode, often used with a producer-consumer model where there are multiple producers and multiple consumers)\n  ├── or_done (a concurrency scenario in which any one task is returned immediately after completion)\n  ├── orderly (keep orderly completion even in concurrent scenarios)\n  ├── map_reduce \n  ├── stream (provides data production stream encapsulation, and implementation of processing streams)\n  ├── pipeline (concurrency becomes serial)\n├── container (containerized component, providing groups, pools, queues)\n  ├── group (provides a lazy loading mode for containers, similar to sync.Pool, which uses a key to get the corresponding container instance when used, or generates it if it doesn\\'t exist)\n  ├── pool (provides a wrapped abstraction of pool, and an implementation of the interface using lists)\n  ├── queue\n    ├── codel (implements a controlled delay algorithm for columns, and sanctions backlogged tasks)\n├── delayed (delayed tasks - standalone version)\n├── distributed (distributed tasks, provides standardized interfaces and corresponding implementations for redis, mysql, pgsql, mongodb)\n├── downgrade (fusion downgrade related components)\n├── egroup (errgroup, controls component lifecycle)\n├── encrypt (Encryption encapsulation, protection padkey complement)\n├── errors (grpc error handling)\n├── gctuner (pre go1.19 gc optimization tool)\n├── generator (number generator, snowflake)\n├── goroutine (provide goroutine pools, control goroutine spikes)\n├── log (interface logging, use logging component to access)\n├── metrics (interface to metrics)\n├── middleware (middleware interface model definition)\n├── net (network related encapsulation)\n  ├── tcp\n├── options (option model interfacing)\n├── overload (server adaptive protection, provides bbr interface, monitors deployed server status to select traffic release, protects server availability)\n  ├── bbr (adaptive flow limiting)\n├── page_token (google aip next token implementation)  \n├── parser (file parsing, proto\u003c-\u003ego mutual parsing)\n  ├── parseGo (parses go to generate pb)\n  ├── parsePb (parses pb to generate go)\n├── registry (service discovery interfacing, google sre subset implementation)\n├── restrictor (restrict flow, provide token bucket and leaky bucket interface wrappers)\n  ├── client_throttling (client throttling)\n  ├── rate \n  ├── ratelimite \n├── structure (common data structure)\n  ├── hashset (hash tables)\n  ├── lscq (lock-free unbounded queue, supports arm)\n  ├── skipmap \n  ├── skipset \n  ├── zset \n├── sync\n    ├── cpu (Get system information for Linux, including cpu mains, cpu usage, etc.)\n    ├── fastrand (random numbers)\n    ├── goid (get goroutine id)\n    ├── mutex (provides trylock, reentrant lock and token reentrant lock)\n    ├── nanotime (timestamp optimization)\n    ├── once (a more powerful implementation of once, set the once function to return an error, and retry if it fails)\n    ├── queue (lock-free queue)\n    ├── safe (underlying string, slice structure)\n    ├── stringx (enhanced version of string)\n    ├── syncx (sync enhancement)\n    ├── xxhash3 \n├── ternary (ternary expressions)    \n├── timeout (timeout control, full link protection, provides some encapsulated implementation of database processing time)\n  ├── ctime (link timeout control)\n  ├── c_json (adapt to database json types)\n  ├── d_time (adapts to database to store time only)\n  ├── date (Adapts database to store dates only)\n  ├── date_struct (Adapts database to store dates only)\n  ├── datetime (adapter database stores datetime)\n  ├── datetime_struct (adapter database stores datetime)\n  ├── stamp (adapter database stores timestamps)\n  ├── human (provides visual time spacing)\n├── tools \n  ├── bind (binding tool, often used with the gin framework to customize the bound data, e.g. binding both query and json)\n  ├── deepcopy (deep copy)\n  ├── float (floating point truncation tool)\n  ├── match (base matcher, match on wildcards)\n  ├── pointer (pointer tool)\n  ├── pretty (formatting json)\n  ├── reflect2value (basic field mapping)\n  ├── rand_string (random strings)\n  ├── vto (assignment of functions with the same type, hands free, usually used for vo-\u003edo object conversions)\n    ├── vtoPlus (adds plus support for field, tag and default value binding)\n├── trace (link tracing)\n├── watching (monitor cpu, mum, gc, goroutine and other metrics, automatically dump pprof metrics in case of fluctuations)\n└── window (sliding window, supports multi-data type metrics window collection)\n\n```\n\n# Download and use\n```shell\ngo get github.com/songzhibin97/gkit\n```\n\n\n## Introduction to the use of components\n## cache\n\nCache-related components\n\u003e buffer \u0026 mbuffer provide similar functionality, buffer has more encapsulation and implements some interfaces to io, while mbuffer is just a memory cache; it is more suitable for short and frequent life cycles.\n\u003e local_cache provides a local data cache, and also has some expiry mechanisms, you can set the expiry time, and regularly clean up the expired data, but he is now older, if needed there is a generic version https://github.com/songzhibin97/go-baseutils/blob/main/ app/bcache\n\u003e singleflight wraps golang.org/x/sync/singleflight to prevent the effects of changes.\n\n\n### buffer pool\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/songzhibin97/gkit/cache/buffer\"\n)\n\nfunc main() {\n\t// Byte reuse\n\n\t// size 2^6 - 2^18\n\t// return an integer multiple of 2 rounded upwards cap, len == size\n\t// Any other special or expanded during runtime will be cleared\n\tslice := buffer.GetBytes(1024)\n\tfmt.Println(len(*slice), cap(*slice)) // 1024 1024\n\n\t// Recycle\n\t// Note: no further references are allowed after recycling\n\tbuffer.PutBytes(slice)\n\n\t// IOByte reuse\n\n\t// io buffer.IoBuffer interface\n\tGetIoPool(1024)\n\n\t// If an object has already been recycled, referring to the recycled object again will trigger an error\n\terr := buffer.PutIoPool(io)\n\tif err != nil {\n\t\t// Handle the error \t    \n\t}\n}\n```\n\n\n### local_cache\n```go\npackage local_cache\n\nimport (\n\t\"github.com/songzhibin97/gkit/cache/buffer\"\n\t\"log\"\n)\n\nvar ch Cache\n\nfunc ExampleNewCache() {\n\t// default configuration\n\t// ch = NewCache()\n\n\t// Optional configuration options\n\n\t// Set the interval time\n\t// SetInternal(interval time.Duration)\n\n\t// Set the default timeout\n\t// SetDefaultExpire(expire time.Duration)\n\n\t// Set the cycle execution function, the default (not set) is to scan the global to clear expired k\n\t// SetFn(fn func())\n\n\t// Set the capture function to be called after the deletion is triggered, the set capture function will be called back after the data is deleted\n\t// SetCapture(capture func(k string, v interface{}))\n\n\t// Set the initialization of the stored member object\n\t// SetMember(m map[string]Iterator)\n\n\tch = NewCache(SetInternal(1000).\n\t\tSetDefaultExpire(10000).\n\t\tSetCapture(func(k string, v interface{}) {\n\t\t\tlog.Println(k, v)\n\t\t}))\n}\n\nfunc ExampleCacheStorage() {\n\t// Set adds cache and overwrites it whether it exists or not\n\tch.Set(\"k1\", \"v1\", DefaultExpire)\n\n\t// SetDefault overrides whether or not it exists\n\t// Default function mode, default timeout is passed in as the default time to create the cache\n\tch.SetDefault(\"k1\", 1)\n\n\t// SetNoExpire\n\t// partial function mode, default timeout is never expired\n\tch.SetNoExpire(\"k1\", 1.1)\n\n\t// Add the cache and throw an exception if it exists\n\terr := ch.Add(\"k1\", nil, DefaultExpire)\n\tCacheErrExist(err) // true\n\n\t// Replace throws an error if it is set or not\n\terr = ch.Replace(\"k2\", make(chan struct{}), DefaultExpire)\n\tCacheErrNoExist(err) // true\n}\n\nfunc ExampleGet() {\n\t// Get the cache based on the key to ensure that kv is removed within the expiration date\n\tv, ok := ch.Get(\"k1\")\n\tif !ok {\n\t\t// v == nil\n\t}\n\t_ = v\n\n\t// GetWithExpire gets the cache based on the key and brings up the timeout\n\tv, t, ok := ch.GetWithExpire(\"k1\")\n\tif !ok {\n\t\t// v == nil\n\t}\n\t// if the timeout is NoExpire t.IsZero() == true\n\tif t.IsZero() {\n\t\t// No timeout is set\n\t}\n\n\t// Iterator returns all valid objects in the cache\n\tmp := ch.Iterator()\n\tfor s, iterator := range mp {\n\t\tlog.Println(s, iterator)\n\t}\n\t\n\t// Count returns the number of members\n\tlog.Println(ch.Count())\n}\n\nfunc ExampleIncrement() {\n\tch.Set(\"k3\", 1, DefaultExpire)\n\tch.Set(\"k4\", 1.1, DefaultExpire)\n\t// Increment adds n to the value corresponding to k n must be a number type\n\terr := ch.Increment(\"k3\", 1)\n\tif CacheErrExpire(err) || CacheErrExist(CacheTypeErr) {\n\t\t// Not set successfully\n\t}\n\t_ = ch.IncrementFloat(\"k4\", 1.1)\n\n\t// If you know the exact type of k to set you can also use the type-determining increment function\n\t// ch.IncrementInt(k string, v int)\n\t// ...\n\t// IncrementFloat32(k string, v flot32) // ch.\n\t// ...\n\n\t// Decrement the same\n}\n\nfunc ExampleDelete() {\n\t// Delete triggers the not-or function if capture is set\n\tch.Delete(\"k1\")\n\n\t// DeleteExpire Deletes all expired keys, the default capture is to execute DeleteExpire()\n\tch.DeleteExpire()\n}\n\nfunc ExampleChangeCapture() {\n\t// Provides a way to change the capture function on the fly\n\t// ChangeCapture\n\tch.ChangeCapture(func(k string, v interface{}) {\n\t\tlog.Println(k, v)\n\t})\n}\n\nfunc ExampleSaveLoad() {\n\t// Write to a file using go's proprietary gob protocol\n\n\tio := buffer.NewIoBuffer(1000)\n\n\t// Save pass in a w io.Writer argument to write the member members of the cache to w\n\t_ = ch.Save(io)\n\n\t// SaveFile pass in a path to write to a file\n\t_ = ch.SaveFile(\"path\")\n\n\t// Load pass in an r io.Reader object read from r and write back to member\n\t_ = ch.Load(io)\n\n\t// LoadFile pass in path to read the contents of the file\n\t_ = ch.LoadFile(\"path\")\n}\n\nfunc ExampleFlush() {\n\t// Flush to free member members\n\tch.Flush()\n}\n\nfunc ExampleShutdown() {\n\t// Shutdown frees the object\n\tch.Shutdown()\n}\n```\n\n### singleflight\n\nMerge back to source\n```go\npackage main\n\nimport (\n\t\"github.com/songzhibin97/gkit/cache/singleflight\"\n)\n\n// getResources: Generally used to go to the database and fetch data\nfunc getResources() (interface{}, error) {\n\treturn \"test\", nil\n}\n\n// cache: populate the cache with data\nfunc cache(v interface{}) {\n\treturn\n}\n\nfunc main() {\n\tf := singleflight.NewSingleFlight()\n\n\t// Synchronize.\n\tv, err, _ := f.Do(\"test1\", func() (interface{}, error) {\n\t\t// Get resources\n\t\treturn getResources()\n\t})\n\tif err != nil {\n\t\t// Handle the error\n\t}\n\t// store to buffer\n\t// v is the fetched resource\n\tcache(v)\n\n\t// asynchronously\n\tch := f.DoChan(\"test2\", func() (interface{}, error) {\n\t\t// Get resources\n\t\treturn getResources()\n\t})\n\n\t// Wait for the resource to be fetched, then return the result via channel\n\tresult := \u003c-ch\n\tif result.Err != nil {\n\t\t// Handle the error\n\t}\n\t\n\t// store to buffer\n\t// result.Val is the fetched resource\n\tcache(result.Val)\n\t\n\t// try to cancel\n\tf.Forget(\"test2\")\n}\n```\n\n\n## coding\n\u003e Object serialization deserialization interface and instance encapsulation, just import anonymous, such as json `_ \"github.com/songzhibin97/gkit/coding/json\"` You can also implement the corresponding interface, after registration, the benefit is to control the global serialization object and the use of library unity\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/songzhibin97/gkit/coding\"\n\t_ \"github.com/songzhibin97/gkit/coding/json\" // Be sure to import ahead of time!!!\n)\n\nfunc main() {\n\tt := struct {\n\t\tGkit string\n\t\tLever int\n\t}{\"Gkit\", 200}\n\tfmt.Println(coding.GetCode(\"json\").Name())\n\tGetCode(\"json\").Marshal(t)\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\treturn\n\t}\n\tfmt.Println(string(data)) // {\"Gkit\": \"Gkit\", \"Lever\":200}\n\tv := struct {\n\t\tGkit string\n\t\tLever int\n\t}{}\n\tcoding.GetCode(\"json\").Unmarshal(data,\u0026v)\n\tfmt.Println(v) // { Gkit 200}\n}\n```\n\n## concurrent\n\n\u003e Best practices for channel in concurrency, including fan_in,fan_out,map_reduce,or_done,orderly,pipeline,stream,generic version can be found at https://github.com/songzhibin97/go-baseutils/tree/main/app/bconcurrent\n\n## container\n\n\u003e Pool, but you can customize the creation function and replace the initialization function.\n\u003e pool pooling object, through the configuration can set the maximum number of connections and the number of waiting connections, synchronous asynchronous acquisition of connections, and connection life cycle management, you can customize the creation function, and replace the initialization function\n\u003e codel implement codel algorithm, can be used to limit the flow, and fuse\n\n### group\n\nLazy loading containers\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/songzhibin97/gkit/container/group\"\n)\n\nfunc createResources() interface{} {\n\treturn map[int]int{1: 1, 2: 2}\n}\n\nfunc createResources2() interface{} {\n\treturn []int{1, 2, 3}\n}\n\nfunc main() {\n\t// Like sync.Pool\n\t// initialize a group\n\tg := group.NewGroup(createResources)\n\n\t// If the key does not exist call the function passed in by NewGroup to create resources\n\t// If it exists, return the information about the created resource\n\tv := g.Get(\"test\")\n\tfmt.Println(v) // map[1:1 2:2]\n\tv.(map[int]int)[1] = 3\n\tfmt.Println(v) // map[1:3 2:2]\n\tv2 := g.Get(\"test\")\n\tfmt.Println(v2) // map[1:3 2:2]\n\n\t// ReSet resets the initialization function and clears the cached key\n\tg.ReSet(createResources2)\n\tv3 := g.Get(\"test\")\n\tfmt.Println(v3) // []int{1,2,3}\n\t\n\t// Clear the cached buffer\n\tg.Clear()\n}\n```\n\n### pool\n\nSimilar to a resource pool\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"github.com/songzhibin97/gkit/container/pool\"\n\t\"time\"\n)\n\nvar p pool.Pool\n\ntype mock map[string]string\n\nfunc (m *mock) Shutdown() error {\n\treturn nil\n}\n\n// getResources: gets resources, returns a resource object that needs to implement the IShutdown interface for resource recycling\nfunc getResources(context.Context) (pool.IShutdown, error) {\n\treturn \u0026mock{\"mockKey\": \"mockValue\"}, nil\n}\n\nfunc main() {\n\t// pool.NewList(options ...)\n\t// default configuration\n\t// p = pool.NewList()\n\n\t// Optional configuration options\n\n\t// Set the number of Pool connections, if == 0 then no limit\n\t// pool.SetActive(100)\n\n\t// Set the maximum number of free connections\n\t// pool.SetIdle(20)\n\n\t// Set idle wait time\n\t// pool.SetIdleTimeout(time.Second)\n\n\t// Set the expected wait\n\t// pool.SetWait(false,time.Second)\n\n\t// Customize the configuration\n\tp = pool.NewList(\n\t\tpool.SetActive(100).\n\t\tpool.SetIdle(20).\n\t\tpool.SetIdleTimeout(time.Second).\n\t\tSetIdleTimeout(time.Second), pool.SetWait(false, time.Second))\n\n\t// New needs to be instantiated, otherwise it will not get the resource in pool.\n\tp.NewQueue(getResources)\n\n\tv, err := p.Get(context.TODO())\n\tif err != nil {\n\t\t// Handle the error\n\t}\n\tfmt.Println(v) // \u0026map[mockKey:mockValue]\n\n\t// Put: Resource recovery\n\t// forceClose: true internally help you call Shutdown to recycle, otherwise determine if it is recyclable and mount it on a list\n\terr = p.Put(context.TODO(), v, false)\n\tif err != nil {\n\t\t// handle the error  \t    \n\t}\n\t\n\t// Shutdown reclaims resources, shutting down all resources\n\t_ = p.Shutdown()\n}\n```\n\n\n### queue\n\ncodel implementation\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"github.com/songzhibin97/gkit/container/queue/codel\"\n\t\"github.com/songzhibin97/gkit/overload/bbr\"\n)\n\nfunc main() {\n\tqueue := codel.NewQueue(codel.SetTarget(40), codel.SetInternal(1000))\n\n\t// start reflects CoDel state information\n\tstart := queue.Stat()\n\tfmt.Println(start)\n\n\tgo func() {\n\t\t// where the actual consumption takes place\n\t\tqueue.Pop()\n\t}()\n\tif err := queue.Push(context.TODO()); err != nil {\n\t\tif err == bbr.LimitExceed {\n\t\t\t// todo handles overload protection errors\n\t\t} else {\n\t\t\t// todo handles other errors\n\t\t}\n\t}\n}\n```\n\n## delayed\n\n\u003e Stand-alone version of the delay task, using the quadruple heap for implementation, you can customize the monitoring signal, as well as the monitoring time, and the number of work co-processes\n\n```go\npackage main\n\nimport \"github.com/songzhibin97/gkit/delayed\"\n\ntype mockDelayed struct {\n\texec int64\n}\n\nfunc (m mockDelayed) Do() {\n}\n\nfunc (m mockDelayed) ExecTime() int64 {\n\treturn m.exec\n}\n\nfunc (m mockDelayed) Identify() string {\n\treturn \"mock\"\n}\n\nfunc main() {\n\t// Create a delayed object\n\t// delayed.SetSingle() sets the monitor signal\n\t// delayed.SetSingleCallback() set the signal callback\n\t// delayed.SetWorkerNumber() sets the worker concurrently\n\t// delayed.SetCheckTime() Set the monitoring time\n\tn := delayed.NewDispatchingDelayed()\n\n\t// add a delayed task\n\tn.AddDelayed(mockDelayed{exec: 1})\n\t\n\t// Force a refresh\n\tn.Refresh()\n\t\n\t// Close\n\tn.Close()\n}\n\n```\n\n## distributed \n\n\u003e Distributed tasks, currently supports db(gorm), mongodb, redis on the backend, redis on the scheduling side, redis on the distributed locking side, including retry mechanisms, and deferred tasks\n\n## downgrade\n\nMeltdown downgrade\n\n```go\n// Same as github.com/afex/hystrix-go, but in an abstract wrapper to avoid the impact of upgrades on the service\npackage main\n\nimport (\n\t\"context\"\n\t\"github.com/afex/hystrix-go/hystrix\"\n\t\"github.com/songzhibin97/gkit/downgrade\"\n)\n\nvar fuse downgrade.Fuse\n\ntype RunFunc = func() error\ntype FallbackFunc = func(error) error\ntype RunFuncC = func(context.Context) error\ntype FallbackFuncC = func(context.Context, error) error\n\nvar outCH = make(chan struct{}, 1)\n\nfunc mockRunFunc() RunFunc {\n\treturn func() error {\n\t\toutCH \u003c- struct{}{}\n\t\treturn nil\n\t}\n}\n\nfunc mockFallbackFunc() FallbackFunc {\n\treturn func(err error) error {\n\t\treturn nil\n\t}\n}\n\nfunc mockRunFuncC() RunFuncC {\n\treturn func(ctx context.Context) error {\n\t\treturn nil\n\t}\n}\n\nfunc mockFallbackFuncC() FallbackFuncC {\n\treturn func(ctx context.Context, err error) error {\n\t\treturn nil\n\t}\n}\n\nfunc main() {\n\t// Get a fuse\n\tfuse = downgrade.NewFuse()\n\n\t// Leave ConfigureCommand unset and go to the default configuration\n\t// hystrix.CommandConfig{} set the parameters\n\tfuse.ConfigureCommand(\"test\", hystrix.CommandConfig{})\n\n\t// Do: execute func() error synchronously, no timeout control until it returns.\n\t// if return error ! = nil then FallbackFunc is triggered to downgrade\n\terr := fuse.Do(\"do\", mockRunFunc(), mockFallbackFunc())\n\tif err != nil {\n\t\t// Handle the error\n\t}\n\n\t// Go: asynchronous execution Return channel\n\tch := fuse.Go(\"go\", mockRunFunc(), mockFallbackFunc())\n\tselect {\n\tcase err = \u003c-ch:\n\t// Handle the error\n\tcase \u003c-outCH:\n\t\tbreak\n\t}\n\n\t// GoC: Do/Go actually ends up calling GoC, the Do master handles the asynchronous process\n\t// GoC can be passed into context to ensure link timeout control\n\tfuse.GoC(context.TODO(), \"goc\", mockRunFuncC(), mockFallbackFuncC())\n}\n```\n\n## egroup\n\n\u003e ErrorGroup, compared with sync.ErrorGroup, adds a fault tolerance mechanism to prevent wild goroutine panic resulting in abnormal system exit\n\n```go\n// errorGroup \n// Cascade control, if a component has an error, all components in the group will be notified to exit\n// Declare lifecycle management\n\npackage main\n\nimport (\n\t\"context\"\n\t\"github.com/songzhibin97/gkit/egroup\"\n\t\"os\"\n\t\"syscall\"\n\t\"time\"\n)\n\nvar admin *egroup.LifeAdmin\n\nfunc mockStart() func(ctx context.Context) error {\n\treturn nil\n}\n\nfunc mockShutdown() func(ctx context.Context) error {\n\treturn nil\n}\n\ntype mockLifeAdminer struct{}\n\nfunc (m *mockLifeAdminer) Start(ctx context.Context) error {\n\treturn nil\n}\n\nfunc (m *mockLifeAdminer) Shutdown(ctx context.Context) error {\n\treturn nil\n}\n\nfunc main() {\n\t// Default configuration\n\t// admin = egroup.NewLifeAdmin()\n\n\t// Optional configuration options\n\n\t// set the start timeout\n\n\t// \u003c= 0 no start timeout, note that shutdown notifications should be handled at shutdown\n\t// egroup.SetStartTimeout(time.Second)\n\n\t// Set the shutdown timeout\n\t// \u003c=0 no start timeout\n\t// egroup.SetStopTimeout(time.Second)\n\n\t// Set the set of signals, and the functions to handle them\n\t// egroup.SetSignal(func(lifeAdmin *LifeAdmin, signal os.Signal) {\n\t// return\n\t// }, signal...)\n\n\tadmin = egroup.NewLifeAdmin(egroup.SetStartTimeout(time.Second), egroup.SetStopTimeout(time.Second),\n\t\tegroup.SetSignal(func(a *egroup.LifeAdmin, signal os.Signal) {\n\t\t\tswitch signal {\n\t\t\tcase syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT:\n\t\t\t\ta.Shutdown()\n\t\t\tdefault:\n\t\t\t}\n\t\t}))\n\t\n\t// Add via struct\n\tadmin.Add(egroup.Member{\n\t\tStart:    mockStart(),\n\t\tShutdown: mockShutdown(),\n\t})\n\n\t// Adapted via interface\n\tadmin.AddMember(\u0026mockLifeAdminer{})\n\n\t// Start\n\tdefer admin.Shutdown()\n\tif err := admin.Start(); err != nil {\n\t\t// Handle errors\n\t\t// normal start will hold main\n\t}\n}\n\nfunc Demo() {\n\t// Full demo\n\tvar _admin = egroup.NewLifeAdmin()\n\n\tsrv := \u0026http.Server{\n\t\tAddr: \":8080\",\n\t}\n\t// Add a task\n\t_admin.Add(egroup.Member{\n\t\tStart: func(ctx context.Context) error {\n\t\t\tfmt.Println(\"http start\")\n\t\t\treturn goroutine.Delegate(ctx, -1, func(ctx context.Context) error {\n\t\t\t\treturn srv.ListenAndServe()\n\t\t\t})\n\t\t},\n\t\tShutdown: func(ctx context.Context) error {\n\t\t\tfmt.Println(\"http shutdown\")\n\t\t\treturn srv.Shutdown(context.Background())\n\t\t},\n\t})\n\t// _admin.Start() start\n\tfmt.Println(\"error\", _admin.Start())\n\tdefer _admin.Shutdown()\n}\n\n```\n\n## encrypt\n\n\u003e Encryption encapsulation, protection padkey complement\n\n## errors\n\nWrapping some error handling\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"time\"\n\t\n\t\"github.com/songzhibin97/gkit/errors\"\n)\nfunc main() {\n\terr := errors.Errorf(http.StatusBadRequest, \"reason\", \"carrying message %s\", \"test\")\n\terr2 := err.AddMetadata(map[string]string{\"time\": time.Now().String()}) // Carry meta information\n\t// err is the original error err2 is the error with meta information\n\tfmt.Println(errors.Is(err,err2)) // ture\n\t// err2 can be parsed to get more information\n\tfmt.Println(err2.Metadata[\"time\"]) // meta\n}\n````\n\n## gctuner\n\n\u003e go pre 1.19 gc optimizer\n\n```go\n\npackage main\n\nimport \"github.com/songzhibin97/gkit/gctuner\"\n\nfunc main() {\n\t// Get mem limit from the host machine or cgroup file.\n\tlimit := 4 * 1024 * 1024 * 1024\n\tthreshold := uint64(float64(limit) * 0.7)\n\n\tgctuner.Tuning(threshold)\n\n\t// Friendly input\n\tgctuner.TuningWithFromHuman(\"1g\")\n\n\t// Auto\n\t// There may be problems with multiple services in one pod.\n\tgctuner.TuningWithAuto(false) // Is it a container? Incoming Boolean\n}\n```\n\n## generator\n\nGenerator\n\n### snowflake\n\nSnowflake algorithm\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/songzhibin97/gkit/generator\"\n\t\"time\"\n)\n\nfunc main() {\n\tids := generator.NewSnowflake(time.Now(), 1)\n\tnid, err := ids.NextID()\n\tif err != nil {\n\t\t// Handle the error\n\t}\n\tfmt.Println(nid)\n}\n\n```\n\n## goroutine\n\n\u003e Pooling, control exceptions caused by wild goroutine panic, can set maximum capacity, idle time, patrol time, stop timeout, log objects\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"github.com/songzhibin97/gkit/goroutine\"\n\t\"time\"\n)\n\nvar gGroup goroutine.GGroup\n\nfunc mockFunc() func() {\n\treturn func() {\n\t\tfmt.Println(\"ok\")\n\t}\n}\n\nfunc main() {\n\t// Default configuration\n\t// gGroup = goroutine.NewGoroutine(context.TODO())\n\n\t// Optional configuration options\n\n\t// set the stop timeout time\n\t// goroutine.SetStopTimeout(time.Second)\n\n\t// Set the log object\n\t// goroutine.SetLogger(\u0026testLogger{})\n\n\t// Set the maximum pool size\n\t// goroutine.SetMax(100)\n\n\tgGroup = goroutine.NewGoroutine(context.TODO(),\n\t\tgoroutine.SetStopTimeout(time.Second),\n\t\tgoroutine.SetMax(100),\n\t)\n\n\t// Add a task\n\tif !gGroup.AddTask(mockFunc()) {\n\t\t// Adding a task failed\n\t}\n\n\t// Add a task with timeout control\n\tif !gGroup.AddTaskN(context.TODO(), mockFunc()) {\n\t\t// Failed to add task\n\t}\n\n\t// Modify the pool maximum size\n\tgGroup.ChangeMax(1000)\n\n\t// Recycle resources\n\t_ = gGroup.Shutdown()\n}\n```\n\n## log\n\nLogging related\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/songzhibin97/gkit/log\"\n)\n\ntype testLogger struct{}\n\nfunc (l *testLogger) Print(kv ...interface{}) {\n\tfmt.Println(kv...)\n}\n\nfunc main() {\n\tlogs := log.NewHelper(log.DefaultLogger)\n\tlogs.Debug(\"debug\", \"v\")\n\tlogs.Debugf(\"%s,%s\", \"debugf\", \"v\")\n\tlogs.Info(\"Info\", \"v\")\n\tlogs.Infof(\"%s,%s\", \"infof\", \"v\")\n\tlogs.Warn(\"Warn\", \"v\")\n\tlogs.Warnf(\"%s,%s\", \"warnf\", \"v\")\n\tlogs.Error(\"Error\", \"v\")\n\tlogs.Errorf(\"%s,%s\", \"errorf\", \"v\")\n\t/*\n\t[debug] message=debugv\n    [debug] message=debugf,v\n    [Info] message=Infov\n    [Info] message=infof,v\n    [Warn] message=Warnv\n    [Warn] message=warnf,v\n    [Error] message=Errorv\n    [Error] message=errorf,v\n\t*/\n\t\n\tlogger := log.DefaultLogger\n\tlogger = log.With(logger, \"ts\", log.DefaultTimestamp, \"caller\", log.DefaultCaller)\n\tlogger.Log(log.LevelInfo, \"msg\", \"helloworld\")\n\t// [Info] ts=2021-06-10T13:41:35+08:00 caller=main.go:8 msg=helloworld\n}\n```\n\n## metrics\n\nProvides a metrics interface for implementing monitoring configurations\n```go\npackage main\n\ntype Counter interface {\n\tWith(lvs ...string) Counter\n\tInc()\n\tAdd(delta float64)\n}\n\n// Gauge is metrics gauge.\ntype Gauge interface {\n\tWith(lvs ...string) Gauge\n\tSet(value float64)\n\tAdd(delta float64)\n\tSub(delta float64)\n}\n\n// Observer is metrics observer.\ntype Observer interface {\n\tWith(lvs ...string) Observer\n\tObserve(float64)\n}\n```\n\n## middleware\n\nMiddleware interface model definition\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"github.com/songzhibin97/gkit/middleware\"\n\t)\n\nfunc annotate(s string) middleware.MiddleWare {\n\treturn func(next middleware.Endpoint) middleware.Endpoint {\n\t\treturn func(ctx context.Context, request interface{}) (interface{}, error) {\n\t\t\tfmt.Println(s, \"pre\")\n\t\t\tdefer fmt.Println(s, \"post\")\n\t\t\treturn next(ctx, request)\n\t\t}\n\t}\n}\n\nfunc myEndpoint(context.Context, interface{}) (interface{}, error) {\n\tfmt.Println(\"my endpoint!\")\n\treturn struct{}{}, nil\n}\n\nvar (\n\tctx = context.Background()\n\treq = struct{}{}\n)\n\nfunc main() {\n    e := middleware.Chain(\n\t\tannotate(\"first\"),\n\t\tannotate(\"second\"),\n\t\tannotate(\"third\"),\n\t)(myEndpoint)\n\n\tif _, err := e(ctx, req); err != nil {\n\t\tpanic(err)\n\t}\n\t// Output.\n\t// first pre\n\t// second pre\n\t// third pre\n\t// my endpoint!\n\t// third post\n\t// second post\n\t// first post\n}\n```\n\n## net\n\nNetwork related encapsulation\n\n### tcp\n```go\n    // Send data to the other side, with a retry mechanism\n    Send(data []byte, retry *Retry) error\n\n    // Accept data\n    // length == 0 Read from Conn once and return immediately\n    // length \u003c 0 Receive all data from Conn and return it until there is no more data\n    // length \u003e 0 Receive the corresponding data from Conn and return it\n    Recv(length int, retry *Retry) ([]byte, error) \n\n    // Read a line of '\\n'\n    RecvLine(retry *Retry) ([]byte, error) \n\n    // Read a link that has timed out\n    RecvWithTimeout(length int, timeout time.Duration, retry *Retry) ([]byte, error) \n\n    // Write data to a link that has timed out\n    SendWithTimeout(data []byte, timeout time.Duration, retry *Retry) error\n\n    // Write data and read back\n    SendRecv(data []byte, length int, retry *Retry) ([]byte, error)\n\n    // Write data to and read from a link that has timed out\n    SendRecvWithTimeout(data []byte, timeout time.Duration, length int, retry *Retry) ([]byte, error)\n```\n\n## options\n\nOptions mode interface\n\n\n## overload\n\u003e Overload protection, internal current limiting using bbr algorithm\n\n**general use**\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"github.com/songzhibin97/gkit/overload\"\n\t\"github.com/songzhibin97/gkit/overload/bbr\"\n)\n\nfunc main() {\n\t// Common use\n\t\n\t// Create the Group first\n\tgroup := bbr.NewGroup()\n\t// If it doesn't exist, it will be created\n\tlimiter := group.Get(\"key\")\n\tf, err := limiter.Allow(context.TODO())\n\tif err != nil {\n\t\t// means it is overloaded and the service is not allowed to access it\n\t\treturn\n\t}\n\t// Op: the actual operation type of the traffic write-back record indicator\n\tf(overload.DoneInfo{Op: overload.Success})\n}\n```\n\n**Middleware application**\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"github.com/songzhibin97/gkit/overload\"\n\t\"github.com/songzhibin97/gkit/overload/bbr\"\n)\n\nfunc main() {\n\t// Common use\n\n\t// Create the Group first\n\tgroup := bbr.NewGroup()\n\t// If it doesn't exist, it will be created\n\tlimiter := group.Get(\"key\")\n\tf, err := limiter.Allow(context.TODO())\n\tif err != nil {\n\t\t// means it is overloaded and the service is not allowed to access it\n\t\treturn\n\t}\n\t// Op: the actual operation type of the traffic write-back record indicator\n\tf(overload.DoneInfo{Op: overload.Success})\n\n\t// Create Group middleware\n\tmiddle := bbr.NewLimiter()\n\n\t// in the middleware \n\t// The ctx carries these two configurable valid data\n\t// You can get the limiter type via the ctx.Set\n\n\t// Configure to get the limiter type, you can get different limiter according to different api\n\tctx := context.WithValue(context.TODO(), bbr.LimitKey, \"key\")\n\n\t// Configurable to report success or not\n\t// must be of type overload.\n\tctx = context.WithValue(ctx, bbr.LimitOp, overload.Success)\n\n\t_ = middle\n}\n```\n\n## page_token\n\u003e https://google.aip.dev/158 Google Pagination\n\u003e The options mode allows you to configure a custom maximum page value, maximum number of elements per page, set the encryption key, and expiration time, page_token to effectively prevent crawlers and page flip attacks, and to limit the interface concurrency.\n\n```go\npackage main\n\nimport \"github.com/songzhibin97/gkit/page_token\"\n\nfunc main() {\n   \tn := NewTokenGenerate(\"test\") // Unique identification of the resource, and the option to pass the above\n\t// 10000 is the total number\n\t// Generate page_token\n\t// start - end start and end address, tk is next_token\n\tstart, end, tk, err := n.ProcessPageTokens(10000, 100, \"\") // 0,100, tk\n\tstart, end, ntk, err := n.ProcessPageTokens(10000, 100, tk) // 100,200,ntk\n\tn.GetIndex(ntk) // 200\n}\n```\n\n## parser\n\nProvides `.go` file to `.pb` and `.pb` to `.go` \n`.go` files to `.pb` are more feature-rich, for example, providing spot staking code injection and de-duplication recognition\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/songzhibin97/gkit/parse/parseGo\"\n\t\"github.com/songzhibin97/gkit/parse/parsePb\"\n)\n\nfunc main() {\n\tpgo, err := parseGo.ParseGo(\"gkit/parse/demo/demo.api\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tr := pgo.(*parseGo.GoParsePB)\n\tfor _, note := range r.Note {\n\t\tfmt.Println(note.Text, note.Pos(), note.End())\n\t}\n\t// Output the string, if you need to import the file yourself\n\tfmt.Println(r.Generate())\n\n\t// Pile injection\n\t_ = r.PileDriving(\"\", \"start\", \"end\", \"var _ = 1\")\n    \n\t// Dismounting\n\t_ = r.PileDismantle(\"var _ = 1\")\n\t\n\tppb, err := parsePb.ParsePb(\"GKit/parse/demo/test.proto\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\t// Output the string, if you need to import the file yourself\n\tfmt.Println(ppb.Generate())\n}\n```\n\n## registry\n\n\u003e Provides a generic interface for registration discovery, external dependencies using the generic interface, and a fixed instance structure\n\u003e Service discovery provides a variety of algorithms, from the common subset algorithm to the latest rock_steadier_subset(https://dl.acm.org/doi/10.1145/3570937)\n\n\n## restrictor\n\nflow limiter\n\n### rate\n\nleakage bucket\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\trate2 \"github.com/songzhibin97/gkit/restrictor/rate\"\n\t\"golang.org/x/time/rate\"\n\t\"time\"\n)\n\nfunc main() {\n\t// The first argument is r Limit, which represents how many tokens can be generated into the Token bucket per second; Limit is actually an alias for float64\n\t// The second argument is b int. b represents the size of the Token bucket.\n\t// limit := Every(100 * time.Millisecond).\n\t// limiter := rate.NewLimiter(limit, 4)\n\t// The above means putting a Token in the bucket every 100ms, which essentially means generating 10 a second.\n\n\t// rate: golang.org/x/time/rate\n\tlimiter := rate.NewLimiter(2, 4)\n\n\taf, wf := rate2.NewRate(limiter)\n\n\t// af.Allow() bool: take 1 token by default\n\t// af.Allow() == af.AllowN(time.Now(), 1)\n\taf.Allow()\n\n\t// af.AllowN(ctx,n) bool: can take N tokens\n\taf.AllowN(time.Now(), 5)\n\n\t// wf.Wait(ctx) err: wait for ctx to time out, default takes 1 token\n\t// wf.Wait(ctx) == wf.WaitN(ctx, 1) \n\t_ = wf.Wait(context.TODO())\n\n\t// wf.WaitN(ctx, n) err: wait for ctx to time out, can take N tokens\n\t_ = wf.WaitN(context.TODO(), 5)\n}\n```\n\n### ratelimite\n\nToken bucket\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"github.com/juju/ratelimit\"\n\tratelimit2 \"github.com/songzhibin97/gkit/restrictor/ratelimite\"\n\t\"time\"\n)\n\nfunc main() {\n\t// ratelimit:github.com/juju/ratelimit\n\tbucket := ratelimit.NewBucket(time.Second/2, 4)\n\n\taf, wf := ratelimit2.NewRateLimit(bucket)\n\t// af.Allow() bool: takes 1 token by default\n\t// af.Allow() == af.AllowN(time.Now(), 1)\n\taf.Allow()\n\n\t// af.AllowN(ctx,n) bool: can take N tokens\n\taf.AllowN(time.Now(), 5)\n\n\t// wf.Wait(ctx) err: wait for ctx to time out, default takes 1 token\n\t// wf.Wait(ctx) == wf.WaitN(ctx, 1) \n\t_ = wf.Wait(context.TODO())\n\n\t// wf.WaitN(ctx, n) err: wait for ctx to time out, can take N tokens\n\t_ = wf.WaitN(context.TODO(), 5)\n}\n```\n\n## structure (common data structures)\n\n### hashset\n\n```go\npackage main\n\nfunc main() {\n\tl := hashset.NewInt()\n\n\tfor _, v := range []int{10, 12, 15} {\n\t\tl.Add(v)\n\t}\n\n\tif l.Contains(10) {\n\t\tfmt.Println(\"hashset contains 10\")\n\t}\n\n\tl.Range(func(value int) bool {\n\t\tfmt.Println(\"hashset range found \", value)\n\t\treturn true\n\t})\n\n\tl.Remove(15)\n\tfmt.Printf(\"hashset contains %d items\\r\\n\", l.Len())\n}\n```\n\n\n### lscq\n\n```go\npackage main\n\nfunc main() {\n    l := lscq.NewUint64()\n\t\n\tok := l.Enqueue(1)\n\tif !ok {\n\t\tpanic(\"enqueue failed\")\n    }   \n\tv, err := l.Dequeue()\n\tif err != nil {\n\t\tpanic(\"dequeue failed\")\n    }\n\tfmt.Println(\"lscq dequeue value:\", v)\n}\n```\n\n\n### skipmap \n\n```go\npackage main\n\nfunc main() {\n     m := skipmap.NewInt()\n\n\t// Correctness.\n\tm.Store(123, \"123\")\n\tm.Load(123)\n\tm.Delete(123)\n\tm.LoadOrStore(123)\n\tm.LoadAndDelete(123)\n}\n```\n\n### skipset \n\n```go\npackage main\nfunc Example() {\n\tl := skipset.NewInt()\n\n\tfor _, v := range []int{10, 12, 15} {\n\t\tif l.Add(v) {\n\t\t\tfmt.Println(\"skipset add\", v)\n\t\t}\n\t}\n\n\tif l.Contains(10) {\n\t\tfmt.Println(\"skipset contains 10\")\n\t}\n\n\tl.Range(func(value int) bool {\n\t\tfmt.Println(\"skipset range found \", value)\n\t\treturn true\n\t})\n\n\tl.Remove(15)\n\tfmt.Printf(\"skipset contains %d items\\r\\n\", l.Len())\n}\n```\n\n\n### zset View corresponding readme \n\n## sys\n### mutex\n    Lock-related wrappers (implements trylock, reentrant locks, etc., reentrant token locks, can also get lock indicator data)\n```go\npackage main\n\nfunc main() {\n     // Get the lock\n    lk := mutex.NewMutex()\n    // Try to get a lock\n    if lk.TryLock() {\n    \t// Get the lock\n    \tdefer lk.Unlock()\n    }\n    // Failed to execute other logic\n    \n    lk.Count() // get the number of locks waiting\n    \n    lk.IsLocked() // whether the lock is held\n    \n    lk.IsWoken() // whether a waiter has been woken up internally\n    \n    lk.IsStarving() // whether it is in starvation mode\n    \n    // Reentrant locks\n    // can be acquired multiple times in the same goroutine\n    rvlk := mutex.NewRecursiveMutex() \n    rvlk.Lock()\n    defer rvlk.Unlock()\n    \n    // token reentrant lock\n    // Pass in the same token to enable the reentrant function\n    tklk := mutex.NewTokenRecursiveMutex()\n    tklk.Lock(token)\n    defer tklk.Unlock(token)\n}\n```\n\n\n## ternary\n\n\u003e Simple implementation of ternary expressions\n\u003e The generic version can be used **[go-baseutils](https://github.com/songzhibin97/go-baseutils/tree/main/base/bternaryexpr)**\n\u003e Be careful not to use the null pointer directly for point arithmetic, as it needs to be called first as an entry, the solution can be to close the incoming function\n\n```go\npackage main\n\nimport \"github.com/songzhibin97/gkit/ternary\"\n\nfunc main() {\n    ternary.ReturnInt(true, 1, 2)  // 1\n}\n```\n\n## timeout\n\n\u003e Timeout control between services (and a structure to handle the time format)\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"github.com/songzhibin97/gkit/timeout\"\n\t\"time\"\n)\n\nfunc main() {\n\t// The timeout.Shrink method provides link-wide timeout control\n\t// Just pass in a ctx of the parent node and the timeout to be set, and he will check for you if the ctx has been set before.\n\t// If the timeout has been set, it will be compared with the timeout you currently set, and the smallest one will be set to ensure that the link timeout is not affected downstream.\n\t// d: represents the remaining timeout period\n\t// nCtx: the new context object\n\t// cancel: returns a cancel() method if the timeout was actually set successfully, or an invalid cancel if it was not, but don't worry, it can still be called normally\n\td, nCtx, cancel := timeout.Shrink(context.Background(), 5*time.Second)\n\t// d as needed \n\t// Generally determine the downstream timeout for the service, if d is too small you can just drop it\n\tselect {\n\tcase \u003c-nCtx.Done():\n\t\tcancel()\n\tdefault:\n\t\t// ...\n\t}\n\t_ = d\n}\n```\nOther(currently, gorm also has a related type that is supported.)\n\u003e timeout.DbJSON // provides some functionality in db json format\n\u003e timeout.DTime // provides some functionality in db 15:04:05 format\n\u003e DateStruct // provides some functionality in db 15:04:05 format Embedded in struct mode\n\u003e Date // provides some functionality in db 2006-01-02 format\n\u003e DateTime // provides some functions in db 2006-01-02 15:04:05 format\n\u003e DateTimeStruct // provides some functions in db 2006-01-02 15:04:05 format Embed mode as struct\n\u003e timeout.Stamp // provides some functionality in db timestamp format\n\n```go\npackage main\n\nimport (\n\t\"github.com/songzhibin97/gkit/timeout\"\n\t\"gorm.io/driver/mysql\"\n\t\"gorm.io/gorm\"\n\t\"time\"\n)\n\ntype GoStruct struct {\n\tDateTime timeout.DateTime\n\tDTime    timeout.DTime\n\tDate     timeout.Date\n}\n\nfunc main() {\n\t// refer to https://github.com/go-sql-driver/mysql#dsn-data-source-name for details\n\tdsn := \"user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4\u0026parseTime=True\u0026loc=Local\"\n\tdb, err := gorm.Open(mysql.Open(dsn), \u0026gorm.Config{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdb.AutoMigrate(\u0026GoStruct{})\n\tdb.Create(\u0026GoStruct{\n\t\tDateTime: timeout.DateTime(time.Now()).\n\t\tDTime: timeout.DTime(time.Now()).\n\t\tDate: timeout.Date(time.Now()).\n\t})\n\tv := \u0026GoStruct{}\n\tdb.Find(v) // successfully found\n}\n\n```\n\n\n\n## tools\n\n### bind\n```go\n\npackage main\n\n// Provide an all-in-one bind tool for gin\nimport (\n\t\"github.com/songzhibin97/gkit/tools/bind\"\n\n\t\"github.com/gin-gonic/gin\"\n)\n\ntype Test struct {\n\tJson string `json: \"json\" form: \"json,default=jjjson\"`\n\tQuery string `json: \"query\" form: \"query\"`\n}\n\nfunc main() {\n\tr := gin.Default()\n\tr.POST(\"test\", func(c * gin.Context) {\n\t\tt := Test{}\n\t\t// url : 127.0.0.1:8080/test?query=query\n\t\t// {\n\t\t// \"json\": \"json\".\n\t\t// \"query\": \"query\"\n\t\t// }\n\t\t// err := c.ShouldBindWith(\u0026t, bind.CreateBindAll(c.ContentType()), bind.)\n\t\t// Custom binding object\n\t\t// err := c.ShouldBindWith(\u0026t, bind.CreateBindAll(c.ContentType(), bind.SetSelectorParse([]bind.Binding{})))\n\t\tif err != nil {\n\t\t\tc.JSON(200, err)\n\t\t\treturn\n\t\t}\n\t\tc.JSON(200, t)\n\t})\n\tr.Run(\":8080\")\n}\n```\n\n### votodo\n```go\npackage main\n\nimport \"github.com/songzhibin97/gkit/tools/vto\"\n\ntype CP struct {\n\tZ1 int `default: \"1\"`\n\tZ2 string `default: \"z2\"`\n}\n\nfunc main() {\n\tc1 := CP{\n\t\tZ1: 22,\n\t\tZ2: \"33\",\n\t}\n\tc2 := CP{}\n\tc3 := CP{}\n\t_ = vto.VoToDo(\u0026c2,\u0026c1)\n\t// c2 CP{ Z1: 22, Z2: \"33\"}\n\t// same name same type execution copy\n\t// must be dst, src must pass pointer type\n\t\n\t// v1.1.2 New default tag\n\t_ = vto.VoToDo(\u0026c2,\u0026c3)\n\t// c2 CP{ Z1: 1, Z2: \"z2\"}\n\t// same name same type execution copy\n\t// must dst, src must pass pointer type\n\t\n}\n```\n\n### votodoPlus\n\nAdded field \u0026tag \u0026 default value\n\n## window\n\nProvide indicator windows\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/songzhibin97/gkit/window\"\n\t\"time\"\n)\nfunc main() {\n\tw := window.NewWindow()\n\tslice := []window.Index{\n\t\t{Name: \"1\", Score: 1}, {Name: \"2\", Score: 2}.\n\t\t{Name: \"2\", Score: 2}, {Name: \"3\", Score: 3}.\n\t\t{Name: \"2\", Score: 2}, {Name: \"3\", Score: 3}.\n\t\t{Name: \"4\", Score: 4}, {Name: \"3\", Score: 3}.\n\t\t{Name: \"5\", Score: 5}, {Name: \"2\", Score: 2}.\n\t\t{Name: \"6\", Score: 6}, {Name: \"5\", Score: 5}.\n\t}\n\t/*\n\t\t\t[{1 1} {2 2}]\n\t\t    [{2 4} {3 3} {1 1}]\n\t\t    [{1 1} {2 6} {3 6}]\n\t\t    [{3 9} {4 4} {1 1} {2 6}]\n\t\t    [{1 1} {2 8} {3 9} {4 4} {5 5}]\n\t\t    [{5 10} {3 9} {2 6} {4 4} {6 6}]\n\t*/\n\tfor i := 0; i \u003c len(slice); i += 2 {\n\t\tw.AddIndex(slice[i].Name, slice[i].Score)\n\t\tw.AddIndex(slice[i+1].Name, slice[i+1].Score)\n\t\ttime.Sleep(time.Second)\n\t\tfmt.Println(w.Show())\n\t}\n}\n```\n\n## trace\nLink tracing\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\tgtrace \"github.com/songzhibin97/gkit/trace\"\n\t\"go.opentelemetry.io/otel/trace\"\n)\n\ntype _Transport struct {\n}\n\nfunc (tr *_Transport) Get(key string) string {\n\tpanic(\"implement me\")\n}\n\nfunc (tr *_Transport) Set(key string, value string) {\n\tpanic(\"implement me\")\n}\n\nfunc (tr *_Transport) Keys() []string {\n\tpanic(\"implement me\")\n}\nfunc main() {\n\t// trace.WithServer() server side using middleware\n\t// trace.WithClient() client using middleware\n\ttracer := gtrace.NewTracer(trace.SpanKindServer)\n\tctx, span := tracer.Start(context.Background(), \"Using gkit\", \u0026_Transport{})\n\tfmt.Println(span)\n\tdefer tracer.End(ctx, span, \"replay\", nil)\n}\n```\n\n## watching\n\nSystem monitoring (includes cpu, mum, gc, goroutine, etc. window monitoring, dump pprof after preset fluctuation values)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsongzhibin97%2Fgkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsongzhibin97%2Fgkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsongzhibin97%2Fgkit/lists"}