Due to AWS API rate limits, we need to minimize API calls as much as possible.
Our stated objectives:
* for all displayed tasks and services to have up-to-date metadata
* for all tasks to map to services if able
My approach here:
* Tasks only contain immutable fields (that we care about). We cache tasks forever.
We only DescribeTasks the first time we see a new task.
* We attempt to match tasks to services with what info we have. Any "referenced" services,
ie. a service with at least one matching task, needs to be updated to refresh changing data.
* In the event that a task doesn't match any of the (updated) services, ie. a new service entirely
needs to be found, we do a full list and detail of all services (we don't re-detail ones we just refreshed).
* To avoid unbounded memory usage, we evict tasks and services from the cache after 1 minute without use.
This should be long enough for things like temporary failures to be glossed over.
This gives us exactly one call per task, and one call per referenced service per report,
which is unavoidable to maintain fresh data. Expensive "describe all" service queries are kept
to only when newly-referenced services appear, which should be rare.
We could make a few very minor improvements here, such as trying to refresh unreferenced but known
services before doing a list query, or getting details one by one when "describing all" and stopping
when all matches have been found, but I believe these would produce very minor, if any, gains in
number of calls while having an unjustifiable effect on latency since we wouldn't be able to do requests
as concurrently.
Speaking of which, this change has a minor performance impact.
Even though we're now doing less calls, we can't do them as concurrently.
Old code:
concurrently:
describe tasks (1 call)
sequentially:
list services (1 call)
describe services (N calls concurrently)
Assuming full concurrency, total latency: 2 end-to-end calls
New code (worst case):
sequentially:
describe tasks (1 call)
describe services (N calls concurrently)
list services (1 call)
describe services (N calls concurrently)
Assuming full concurrency, total latency: 4 end-to-end calls
In practical terms, I don't expect this to matter.
Instead of different usage info for "scope help", show the same always.
Also correct it for what the script actually does,
and always display the scope binary args.
As indicated by the TODO, any args passed into the command do not get escaped
when output, so for example:
scope command "foo bar"
would output results like:
foo bar
instead of
"foo bar"
or
foo\ bar
The "right" way to do this seems to be printf %q, which prints a quoted version of the string.
However this format specifier is not available in POSIX sh (though it does work in many
implementations of it, such as the ones provided by bash which make up the likely majority of
real-world usage).
This code is a compromise that uses the added functionality where available,
while still falling back to the old behaviour when it isn't.
By far the majority of these were variables which were not quoted.
While, yes, right now we can guarentee most of these variables will never contain spaces,
this could someday change and applying quoting as a universal rule prevents future mistakes.
The ARGS="$@" -> "$*" change is purely stylistic and mainly is used to indicate the intent that
we actually wanted to concatenate all the args by spaces, not keep them seperated as "$@" would
in many situations, but not this one.
Several warnings remain, in places where we intentionally want to split a variable on whitespace,
or otherwise do what shellcheck is warning us against.
Of note is shellcheck warning SC2166, which says to prefer [ foo ] || [ bar ] over [ foo -o bar ]
as the -a and -o flags have differing behaviour on some systems.
I've opted to keep these for now, since the version check test command would need to be replaced by
a LOT of subshells to achieve the same effect, which feels dirtier.