Skip to content
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

refactor!: Update App Concurrency Model #30

Merged
merged 42 commits into from
Oct 3, 2022
Merged

refactor!: Update App Concurrency Model #30

merged 42 commits into from
Oct 3, 2022

Conversation

jshlbrd
Copy link
Contributor

@jshlbrd jshlbrd commented Oct 1, 2022

Description

  • Refactors the core application's concurrency model to use errgroup
  • Changes all application errors from public to private
  • Changes the internal DynamoDB Query API to refer to partition keys as :pk and sort keys as :sk
    • This follows best practices for the DynamoDB key condition expression syntax
  • Standardizes the system's naming conventions and design patterns

Motivation and Context

For the concurrency model refactor, we've known for a while that the existing design has a risk of leaking goroutines when data processing errors happen, but fixing this wasn't a priority because we've never observed it as an issue since the system runs in AWS Lambda (over time the "serverless container" that the application runs in is reaped, cleaning up lingering goroutines).

Now is as good a time as any to try and improve the design, so this PR replaces the Errs and Kill channels with an errgroup and derived context. Functionally this is the same, but provides two advantages for reliability:

  • we're no longer using buffered channels
  • errors safely propagate across goroutines

The only significant change in this refactor is the introduction of a Channel struct that allows safer closing of and writing to channels. This was required to interrupt producer goroutines stuck on unbuffered channels when the consumer already terminated, but has an advantage of future proofing changes we might make to channel behavior.

References for these changes:

For the remaining changes, I think they are self-explanatory -- mostly focused on standardizing our approach to conventions across the system with supported documentation.

How Has This Been Tested?

  • Added a unit test for cmd/app that uses Uber's goleak package to test for goroutine leaks
    • Unrelated to testing, cmd/app_test.go contains a fully functional Substation app that can be used as a toy example
  • Tested on two large, complex deployments

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.

@jshlbrd jshlbrd marked this pull request as ready for review October 3, 2022 14:56
@jshlbrd jshlbrd requested a review from a team as a code owner October 3, 2022 14:56
Copy link
Contributor

@shellcromancer shellcromancer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice refactor!

config/config_test.go Show resolved Hide resolved
select {
case <-kill:
case <-ctx.Done():
return nil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this return ctx.Err() as well as the others?

@@ -11,7 +11,7 @@ import (
)

/*
ForEach processes data by iterating and applying a processor to each element in a JSON array. The processor supports these patterns:
ForEach processes data by iterating anding a processor to each element in a JSON array. The processor supports these patterns:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: grammatical error here

@@ -44,7 +44,7 @@ type ForEach struct {
/*
ForEachOptions contains custom options for the ForEach processor:
Processor:
processor to apply to the data
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: grammatical error here

process/math.go Outdated
@@ -9,7 +9,7 @@ import (
)

/*
Math processes data by applying mathematic operations. The processor supports these patterns:
Math processes data bying mathematic operations. The processor supports these patterns:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: grammatical error here


/*
Pipeline processes data by applying a series of processors. This processor should be used when data requires complex processing outside of the boundaries of any data structures (see tests for examples). The processor supports these patterns:
Pipeline processes data bying a series of processors. This processor should be used when data requires complex processing outside of the boundaries of any data structures (see tests for examples). The processor supports these patterns:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: grammatical error here

@@ -58,7 +58,7 @@ type Pipeline struct {
/*
PipelineOptions contains custom options for the Pipeline processor:
Processors:
array of processors to apply to the data
array of processors to to the data
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: grammatical error here


/*
PrettyPrint processes data by applying or reversing prettyprint formatting to JSON.
PrettyPrint processes data bying or reversing prettyprint formatting to JSON.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: grammatical error

Copy link
Contributor

@julieagnessparks julieagnessparks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Left a couple comments on typos in documentation but NBD

@@ -2,26 +2,307 @@

Thank you so much for your interest in contributing to Substation! This document contains guidelines to follow when contributing to the project.

## Table Of Contents
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow love the reformatting of the documentation 👏🏻

process/hash.go Outdated
@@ -43,7 +45,7 @@ type Hash struct {
/*
HashOptions contains custom options for the Hash processor:
Algorithm:
the hashing algorithm to apply
the hashing algorithm to
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: the hashing algorithm to must be..

process/math.go Outdated
@@ -9,7 +9,7 @@ import (
)

/*
Math processes data by applying mathematic operations. The processor supports these patterns:
Math processes data bying mathematic operations. The processor supports these patterns:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: by applying


/*
Pipeline processes data by applying a series of processors. This processor should be used when data requires complex processing outside of the boundaries of any data structures (see tests for examples). The processor supports these patterns:
Pipeline processes data bying a series of processors. This processor should be used when data requires complex processing outside of the boundaries of any data structures (see tests for examples). The processor supports these patterns:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: by applying


/*
PrettyPrint processes data by applying or reversing prettyprint formatting to JSON.
PrettyPrint processes data bying or reversing prettyprint formatting to JSON.
This processor has significant limitations when used to reverse prettyprint, including:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: by applying

@@ -322,7 +319,7 @@ func newBatch(s *[]config.Capsule) []config.Capsule {
return make([]config.Capsule, 0, 10)
}

// conditionallyApplyBatch uses conditions to dynamically apply processors to a slice of encapsulated data. This is a convenience function for the ApplyBatch method used in most processors.
// conditionallyApplyBatch uses conditions to dynamically processors to a slice of encapsulated data. This is a convenience function for the ApplyBatch method used in most processors.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: to dynamically apply processors

@jshlbrd jshlbrd merged commit d8df4e2 into main Oct 3, 2022
@jshlbrd jshlbrd deleted the errgroups branch October 3, 2022 17:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants