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

Add a CloudWatchRecorder builder #25

Merged
merged 1 commit into from
Jul 3, 2018

Conversation

MasonHM
Copy link

@MasonHM MasonHM commented Jun 27, 2018

The builder allows passing in a ScheduledExecutorService for additional
control over metric publishing execution.

This replaces pull request #5 by allowing the customer to inject exception handling if they need it.

@MasonHM
Copy link
Author

MasonHM commented Jun 27, 2018

Example ScheduledExecutorService to wrap the Runnable so that it will catch exceptions, log them, and then survive:

    public class LogAndDropScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor {
        private ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();

        public LogAndDropScheduledThreadPoolExecutor() {
            this(1);
        }

        public LogAndDropScheduledThreadPoolExecutor(int corePoolSize) {
            super(corePoolSize);
        }

        @Override
        public void execute(Runnable command) {
            executorService.execute(() -> {
                try {
                    command.run();
                } catch (Throwable t) {
                    // log and do nothing
                    log.error("Problem encountered during Runnable execution", t);
                }
            });
        }

        @Override
        public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                long initialDelay,
                long period,
                TimeUnit unit) {
            return executorService.scheduleAtFixedRate(() -> {
                try {
                    command.run();
                } catch (Throwable t) {
                    // log and do nothing
                    log.error("Problem encountered during Runnable execution", t);
                }
            }, initialDelay, period, unit);
        }
    }

Example ScheduledExecutorService to log exceptions after execution and then die:

    public class LogAndDieScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor {

        public LogAndDieScheduledThreadPoolExecutor() {
            this(1);
        }

        public LogAndDieScheduledThreadPoolExecutor(int corePoolSize) {
            super(corePoolSize);
        }

        @Override
        protected void afterExecute(Runnable r, Throwable t) {
            super.afterExecute(r, t);
            if (t == null && r instanceof Future<?>) {
                try {
                    Object result = ((Future<?>) r).get();
                } catch (CancellationException ce) {
                    t = ce;
                } catch (ExecutionException ee) {
                    t = ee.getCause();
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt(); // ignore/reset
                }
            }
            if (t != null) {
                log.error("Problem encountered during Runnable execution. Shutting down executor", t);
            }
        }
    }

@@ -117,11 +181,16 @@
*
* @param namespace CloudWatch namespace to publish under.
* @return A CloudWatchRecorder instance that will automatically shutdown on JVM exit.
* @deprecated Use {@link CloudWatchRecorder.Builder} instead
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to deprecate these constructors?

While I agree that some customers will prefer the builder I also think some may prefer the constructors as well. Maintaining both can present some challenges (e.g. keeping defaults in sync) but as library vendors I'm not sure this is somewhere we need to be opinionated about how someone uses our library.

Copy link
Author

Choose a reason for hiding this comment

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

No, they don't need to be deprecated. They would be phased out in the ideal case, but I'm not in a position to drive the deprecation campaign, so I'm fine with leaving them as-is and adding the builder.

* to CloudWatch for each metric event.
* @param scheduledExecutorService Executor to schedule metric publishing at a fixed rate.
*/
private CloudWatchRecorder(
Copy link
Contributor

Choose a reason for hiding this comment

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

In the same vein does this need to be private? Potential cost of it being public is?

Builder does no null or error checking, so I don't think exposing this increases the risk that customers will use this in error.

Copy link
Author

Choose a reason for hiding this comment

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

Similar to my other comment, if we're going to support both constructors and the builder moving forward, this can be made public.

The builder allows passing in a ScheduledExecutorService for additional
control over metric publishing execution. It also adds an additional
constructor for the same purpose.
@@ -201,7 +261,46 @@ public CloudWatchRecorder(
final String namespace,
final int maxJitter,
final int publishFrequency,
final DimensionMapper dimensionMapper)
final DimensionMapper dimensionMapper) {
this(
Copy link
Contributor

Choose a reason for hiding this comment

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

It's weird that this doesn't use a builder? The remaining constructors do.

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.

2 participants