Skip to content

Commit

Permalink
Nested goroutines+context exercise
Browse files Browse the repository at this point in the history
  • Loading branch information
rg0now committed Aug 30, 2024
1 parent af7354b commit 53f583e
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 0 deletions.
40 changes: 40 additions & 0 deletions 22-goroutines/06-context/.README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Nested Goroutines

In this exercise, you'll practice using contexts to manage nested goroutines in Go. Your task is to
implement two functions: one that starts a long-running operation in a separate goroutine, and
another that performs the actual long-running operation. You'll use contexts to manage the lifetime
of these goroutines and implement a cancellation mechanism that allows the caller to stop both
goroutines.

The two function signatures:

```go
func StartTask(ctx context.Context) (result string, err error)
func SubTask(ctx context.Context) (result string, err error)
```

Requirements:

1. `StartTask` should:
- Create a new context with a 1-second timeout, derived from the input context.
- Start `SubTask` in a new goroutine using the derived context.
- If the main context is canceled, cancel the subtask and return with an empty string and the
error provided by the main context (use [`ctx.Err()`](https://pkg.go.dev/context#Context)).
- If `SubTask` finishes with a non-empty error, return that error with an empty string.
- Otherwise return whatever string `SubTask` returns prepended with the string `"Main task
status:"` and a `nil` error.

2. `SubTask` should:
- Simulate a long-running task by attempting to run for 200 milliseconds.
- If the provided context is canceled before the task completes, return immediately with the
error provided by the context (use [`ctx.Err()`](https://pkg.go.dev/context#Context)).
- Otherwise, return the string `"Subtask completed successfully"` with an empty error.

3. Use channels to communicate the subtask result and errors between the goroutines. Make sure to
close the channels in the goroutine that actually writes the channels otherwise you will see
ugly race conditions and random panics.

4. Ensure proper resource cleanup by using `defer` statements where appropriate.

Insert the code into the file `exercise.go` at the placeholder `// INSERT YOUR CODE HERE`.

50 changes: 50 additions & 0 deletions 22-goroutines/06-context/.exercise_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package subtask

import (
"context"
"testing"
"time"
)

func TestStartLongRunningTask(t *testing.T) {
t.Run("Successful completion", func(t *testing.T) {
ctx := context.Background()
result, err := StartTask(ctx)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
if result != "Main task status: Subtask completed successfully" &&
result != "Main task status:Subtask completed successfully" {
t.Errorf("Expected 'Main task status:Subtask completed successfully', got %s", result)
}
})

t.Run("Cancelled by main context", func(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
go func() {
time.Sleep(100 * time.Millisecond)
cancel()
}()

result, err := StartTask(ctx)
if err == nil {
t.Error("Expected an error, got nil")
}
if result != "" {
t.Errorf("Expected empty result, got %s", result)
}
})

t.Run("Immediate cancellation", func(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
cancel() // Cancel immediately

result, err := StartTask(ctx)
if err == nil {
t.Error("Expected an error, got nil")
}
if result != "" {
t.Errorf("Expected empty result, got %s", result)
}
})
}
1 change: 1 addition & 0 deletions 22-goroutines/06-context/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# PLEASE RUN make generate
6 changes: 6 additions & 0 deletions 22-goroutines/06-context/exercise.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package subtask

// DO NOT REMOVE THIS COMMENT
//go:generate go run ../../exercises-cli.go -student-id=$STUDENT_ID generate

// INSERT YOUR CODE HERE
1 change: 1 addition & 0 deletions 22-goroutines/06-context/exercise.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
name: subtask
1 change: 1 addition & 0 deletions 22-goroutines/06-context/exercise_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// PLEASE RUN make generate

0 comments on commit 53f583e

Please sign in to comment.