Исходники и презентации
This commit is contained in:
29
lessons/contexts/after_done/main.go
Normal file
29
lessons/contexts/after_done/main.go
Normal file
@ -0,0 +1,29 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// context.AfterFunc
|
||||
|
||||
func WithCtxAfterFunc(ctx context.Context, action func()) {
|
||||
if action != nil {
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
action()
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
WithCtxAfterFunc(ctx, func() {
|
||||
fmt.Println("after")
|
||||
})
|
||||
|
||||
cancel()
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
17
lessons/contexts/chech_cancel/main.go
Normal file
17
lessons/contexts/chech_cancel/main.go
Normal file
@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
import "context"
|
||||
|
||||
func incorrectCheck(ctx context.Context, stream <-chan string) {
|
||||
data := <-stream
|
||||
_ = data
|
||||
}
|
||||
|
||||
func correctCheck(ctx context.Context, stream <-chan string) {
|
||||
select {
|
||||
case data := <-stream:
|
||||
_ = data
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
26
lessons/contexts/context_handling/main.go
Normal file
26
lessons/contexts/context_handling/main.go
Normal file
@ -0,0 +1,26 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Query(string) string
|
||||
|
||||
func DoQeury(qyeryStr string) (string, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
|
||||
defer cancel()
|
||||
|
||||
var resultCh chan string
|
||||
go func() {
|
||||
result := Query(qyeryStr)
|
||||
resultCh <- result
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return "", ctx.Err()
|
||||
case result := <-resultCh:
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
29
lessons/contexts/context_inheritance_1/main.go
Normal file
29
lessons/contexts/context_inheritance_1/main.go
Normal file
@ -0,0 +1,29 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel()
|
||||
|
||||
makeRequest(ctx)
|
||||
}
|
||||
|
||||
func makeRequest(ctx context.Context) {
|
||||
timer := time.NewTimer(5 * time.Second)
|
||||
defer timer.Stop()
|
||||
|
||||
newCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
select {
|
||||
case <-newCtx.Done():
|
||||
fmt.Println("canceled")
|
||||
case <-timer.C:
|
||||
fmt.Println("timer")
|
||||
}
|
||||
}
|
||||
19
lessons/contexts/context_inheritance_2/main.go
Normal file
19
lessons/contexts/context_inheritance_2/main.go
Normal file
@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
_, cancel = context.WithCancel(ctx)
|
||||
cancel()
|
||||
|
||||
if ctx.Err() != nil {
|
||||
fmt.Println("canceled")
|
||||
}
|
||||
}
|
||||
44
lessons/contexts/context_with_cancel/main.go
Normal file
44
lessons/contexts/context_with_cancel/main.go
Normal file
@ -0,0 +1,44 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
func receiveWeather(ctx context.Context, result chan struct{}, idx int) {
|
||||
randomTime := time.Duration(rand.Intn(5000)) * time.Millisecond
|
||||
|
||||
timer := time.NewTimer(randomTime)
|
||||
defer timer.Stop()
|
||||
|
||||
select {
|
||||
case <-timer.C:
|
||||
fmt.Printf("finished: %d\n", idx)
|
||||
result <- struct{}{}
|
||||
case <-ctx.Done():
|
||||
fmt.Printf("canceled: %d\n", idx)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(10)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
result := make(chan struct{}, 10)
|
||||
for i := 0; i < 10; i++ {
|
||||
go func(idx int) {
|
||||
defer wg.Done()
|
||||
receiveWeather(ctx, result, idx)
|
||||
}(i)
|
||||
}
|
||||
|
||||
<-result
|
||||
cancel()
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
15
lessons/contexts/context_with_cancel_cause/main.go
Normal file
15
lessons/contexts/context_with_cancel_cause/main.go
Normal file
@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancelCause(context.Background())
|
||||
cancel(errors.New("error"))
|
||||
|
||||
fmt.Println(ctx.Err())
|
||||
fmt.Println(context.Cause(ctx))
|
||||
}
|
||||
22
lessons/contexts/context_with_http_client/main.go
Normal file
22
lessons/contexts/context_with_http_client/main.go
Normal file
@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://example.com", nil)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
|
||||
if _, err = http.DefaultClient.Do(req); err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
}
|
||||
34
lessons/contexts/context_with_http_server/main.go
Normal file
34
lessons/contexts/context_with_http_server/main.go
Normal file
@ -0,0 +1,34 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
helloWorldHandler := http.HandlerFunc(handle)
|
||||
http.Handle("/welcome", injectTraceID(helloWorldHandler))
|
||||
_ = http.ListenAndServe(":8080", nil)
|
||||
}
|
||||
|
||||
func handle(_ http.ResponseWriter, r *http.Request) {
|
||||
value, ok := r.Context().Value("trace_id").(string)
|
||||
if ok {
|
||||
fmt.Println(value)
|
||||
}
|
||||
|
||||
makeRequest(r.Context())
|
||||
}
|
||||
|
||||
func makeRequest(_ context.Context) {
|
||||
// requesting to database with context
|
||||
}
|
||||
|
||||
func injectTraceID(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := context.WithValue(r.Context(), "trace_id", "12-21-33")
|
||||
req := r.WithContext(ctx)
|
||||
next.ServeHTTP(w, req)
|
||||
})
|
||||
}
|
||||
26
lessons/contexts/context_with_timeout/main.go
Normal file
26
lessons/contexts/context_with_timeout/main.go
Normal file
@ -0,0 +1,26 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func makeRequest(ctx context.Context) {
|
||||
timer := time.NewTimer(5 * time.Second)
|
||||
defer timer.Stop()
|
||||
|
||||
select {
|
||||
case <-timer.C:
|
||||
fmt.Println("finished")
|
||||
case <-ctx.Done():
|
||||
fmt.Println("canceled")
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||
defer cancel()
|
||||
|
||||
makeRequest(ctx)
|
||||
}
|
||||
18
lessons/contexts/context_with_timeout_cause/main.go
Normal file
18
lessons/contexts/context_with_timeout_cause/main.go
Normal file
@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithTimeoutCause(context.Background(), time.Second, errors.New("timeout"))
|
||||
defer cancel() // show difference
|
||||
|
||||
<-ctx.Done()
|
||||
|
||||
fmt.Println(ctx.Err())
|
||||
fmt.Println(context.Cause(ctx))
|
||||
}
|
||||
81
lessons/contexts/context_with_timeout_implementation/main.go
Normal file
81
lessons/contexts/context_with_timeout_implementation/main.go
Normal file
@ -0,0 +1,81 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Context struct {
|
||||
done chan struct{}
|
||||
closed int32
|
||||
}
|
||||
|
||||
func WithTimeout(parent Context, duration time.Duration) (*Context, func()) {
|
||||
if atomic.LoadInt32(&parent.closed) == 1 {
|
||||
return nil, nil // don't use nil
|
||||
}
|
||||
|
||||
ctx := &Context{
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
|
||||
cancel := func() {
|
||||
if atomic.CompareAndSwapInt32(&ctx.closed, 0, 1) {
|
||||
close(ctx.done)
|
||||
}
|
||||
}
|
||||
|
||||
go func() {
|
||||
timer := time.NewTimer(duration)
|
||||
defer timer.Stop()
|
||||
|
||||
select {
|
||||
case <-parent.Done():
|
||||
case <-timer.C:
|
||||
}
|
||||
|
||||
cancel()
|
||||
}()
|
||||
|
||||
return ctx, cancel
|
||||
}
|
||||
|
||||
func (c *Context) Done() <-chan struct{} {
|
||||
return c.done
|
||||
}
|
||||
|
||||
func (c *Context) Err() error {
|
||||
select {
|
||||
case <-c.done:
|
||||
return errors.New("context deadline exceeded")
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Context) Deadline() (time.Time, bool) {
|
||||
// not implemented
|
||||
return time.Time{}, false
|
||||
}
|
||||
|
||||
func (c *Context) Value(any) any {
|
||||
// not implemented
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
ctx, cancel := WithTimeout(Context{}, time.Second)
|
||||
defer cancel()
|
||||
|
||||
timer := time.NewTimer(5 * time.Second)
|
||||
defer timer.Stop()
|
||||
|
||||
select {
|
||||
case <-timer.C:
|
||||
fmt.Println("finished")
|
||||
case <-ctx.Done():
|
||||
fmt.Println("canceled")
|
||||
}
|
||||
}
|
||||
29
lessons/contexts/context_with_value/main.go
Normal file
29
lessons/contexts/context_with_value/main.go
Normal file
@ -0,0 +1,29 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
traceCtx := context.WithValue(context.Background(), "trace_id", "12-21-33")
|
||||
makeRequest(traceCtx)
|
||||
|
||||
oldValue, ok := traceCtx.Value("trace_id").(string)
|
||||
if ok {
|
||||
fmt.Println("mainValue", oldValue)
|
||||
}
|
||||
}
|
||||
|
||||
func makeRequest(ctx context.Context) {
|
||||
oldValue, ok := ctx.Value("trace_id").(string)
|
||||
if ok {
|
||||
fmt.Println("oldValue", oldValue)
|
||||
}
|
||||
|
||||
newCtx := context.WithValue(ctx, "trace_id", "22-22-22")
|
||||
newValue, ok := newCtx.Value("trace_id").(string)
|
||||
if ok {
|
||||
fmt.Println("newValue", newValue)
|
||||
}
|
||||
}
|
||||
26
lessons/contexts/context_with_value_inheritance/main.go
Normal file
26
lessons/contexts/context_with_value_inheritance/main.go
Normal file
@ -0,0 +1,26 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
traceCtx := context.WithValue(context.Background(), "trace_id", "12-21-33")
|
||||
makeRequest(traceCtx)
|
||||
}
|
||||
|
||||
func makeRequest(ctx context.Context) {
|
||||
oldValue, ok := ctx.Value("trace_id").(string)
|
||||
if ok {
|
||||
fmt.Println(oldValue)
|
||||
}
|
||||
|
||||
newCtx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
newValue, ok := newCtx.Value("trace_id").(string)
|
||||
if ok {
|
||||
fmt.Println(newValue)
|
||||
}
|
||||
}
|
||||
27
lessons/contexts/context_with_value_type/main.go
Normal file
27
lessons/contexts/context_with_value_type/main.go
Normal file
@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
{
|
||||
ctx := context.WithValue(context.Background(), "key", "value1")
|
||||
ctx = context.WithValue(ctx, "key", "value2")
|
||||
|
||||
fmt.Println("string =", ctx.Value("key").(string))
|
||||
}
|
||||
{
|
||||
type key1 string // type definition, not type alias
|
||||
type key2 string // type definition, not type alias
|
||||
const k1 key1 = "key"
|
||||
const k2 key2 = "key"
|
||||
|
||||
ctx := context.WithValue(context.Background(), k1, "value1")
|
||||
ctx = context.WithValue(ctx, k2, "value2")
|
||||
|
||||
fmt.Println("key1 =", ctx.Value(k1).(string))
|
||||
fmt.Println("key2 =", ctx.Value(k2).(string))
|
||||
}
|
||||
}
|
||||
17
lessons/contexts/context_without_cancel/main.go
Normal file
17
lessons/contexts/context_without_cancel/main.go
Normal file
@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
innerCtx := context.WithoutCancel(ctx)
|
||||
cancel()
|
||||
|
||||
if innerCtx.Err() != nil {
|
||||
fmt.Println("canceled")
|
||||
}
|
||||
}
|
||||
5
lessons/contexts/errgroup_with_ctx/go.mod
Normal file
5
lessons/contexts/errgroup_with_ctx/go.mod
Normal file
@ -0,0 +1,5 @@
|
||||
module errgroup
|
||||
|
||||
go 1.20
|
||||
|
||||
require golang.org/x/sync v0.6.0
|
||||
2
lessons/contexts/errgroup_with_ctx/go.sum
Normal file
2
lessons/contexts/errgroup_with_ctx/go.sum
Normal file
@ -0,0 +1,2 @@
|
||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
39
lessons/contexts/errgroup_with_ctx/main.go
Normal file
39
lessons/contexts/errgroup_with_ctx/main.go
Normal file
@ -0,0 +1,39 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
group, groupCtx := errgroup.WithContext(ctx)
|
||||
for i := 0; i < 10; i++ {
|
||||
group.Go(func() error {
|
||||
timeout := time.Second * time.Duration(rand.Intn(10))
|
||||
|
||||
timer := time.NewTimer(timeout)
|
||||
defer timer.Stop()
|
||||
|
||||
select {
|
||||
case <-timer.C:
|
||||
fmt.Println("timeout")
|
||||
return errors.New("error")
|
||||
case <-groupCtx.Done():
|
||||
fmt.Println("canceled")
|
||||
return nil
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if err := group.Wait(); err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
}
|
||||
43
lessons/contexts/graceful_shutdown/main.go
Normal file
43
lessons/contexts/graceful_shutdown/main.go
Normal file
@ -0,0 +1,43 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
|
||||
defer stop()
|
||||
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
_, _ = io.WriteString(w, "hello world\n")
|
||||
})
|
||||
|
||||
server := &http.Server{
|
||||
Addr: ":8888",
|
||||
}
|
||||
|
||||
go func() {
|
||||
err := server.ListenAndServe()
|
||||
if err != nil && err != http.ErrServerClosed {
|
||||
log.Print(err.Error()) // exit
|
||||
}
|
||||
}()
|
||||
|
||||
<-ctx.Done()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||
cancel()
|
||||
|
||||
if err := server.Shutdown(ctx); err != nil {
|
||||
log.Print(err.Error())
|
||||
}
|
||||
|
||||
fmt.Println("canceled")
|
||||
}
|
||||
15
lessons/contexts/nil_context/main.go
Normal file
15
lessons/contexts/nil_context/main.go
Normal file
@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
func process(ctx context.Context) {
|
||||
if ctx.Err() != nil {
|
||||
// handling...
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
process(nil)
|
||||
}
|
||||
18
lessons/contexts/with_ctx_check/main.go
Normal file
18
lessons/contexts/with_ctx_check/main.go
Normal file
@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
import "context"
|
||||
|
||||
func WithContexCheck(ctx context.Context, action func()) {
|
||||
if action == nil || ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
|
||||
action()
|
||||
}
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
WithContexCheck(ctx, func() {
|
||||
// do something
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user