Coder Social home page Coder Social logo

mattnworb / futuristic-feline Goto Github PK

View Code? Open in Web Editor NEW

This project forked from spotify/futuristic-feline

0.0 2.0 0.0 560 KB

futuristic-feline is a library for detecting blocking Java futures at runtime

License: Apache License 2.0

Java 100.00%

futuristic-feline's Introduction

futuristic-feline

futuristic-feline is a library for detecting blocking Java futures at runtime. It is inspired by the excellent BlockHound.

Writing asynchronous code is hard and blocking futures can lead to thread pool starvation. This has been a common source of incidents at Spotify and we monitor our services with this library to detect and fix services at risk.

What does it do?

futuristic-feline detects when Future.get(), CompletableFuture.get, or CompletableFuture.join is called in a blocking fashion. That is, if they are called before being completed. futuristic-feline does this by injecting a check into these methods using byte code manipulation, and provides a callback function where you can act on any blocking calls, for example by collecting metrics or failing.

For example, the following will print to stdout on any blocking calls:

Feline.addConsumerLast(System.out::println);

or throw an exception:

Feline.addConsumerLast(call -> {throw new RuntimeException(call);});

To get started, add a dependency on:

    <dependency>
      <groupId>com.spotify</groupId>
      <artifactId>futuristic-feline</artifactId>
      <version>$VERSION</version>
    </dependency>

Build status

Build status

Maven central

Maven Central

Metrics integration

It is often useful to create a metric for the rate of blocking calls. At Spotify we have built this into our service framework using semantic-metrics.

If you use a different metrics collection framework, it should be straight-forward to integrate futuristic-feline. We're happy to accept contributions for other framework integrations.

semantic-metrics integration

Add a dependency on:

    <dependency>
      <groupId>com.spotify</groupId>
      <artifactId>futuristic-feline-semantic-metrics</artifactId>
      <version>$VERSION</version>
    </dependency>

Then install the FelineMetricsRecorder:

FelineMetricsRecorder.install(new SemanticMetricRegistry());

This will create a meter tagged with what: blocking-calls and call referring to the class and method name that called the blocking Future or CompletableFuture method. There is also a tag with thread_name referring to the thread that called the blocking method. To prevent a metrics cardinality explosion, this name is sanitized by replacing all integers with the character N.

Similarly, there's a meter to measure total time blocked: what: blocking-calls-time measured in nano-seconds (also tagged with unit: ns) with the same tags as above (call and thread_name).

You can customize how the caller is identified by injecting a custom CallFinder to the FelineMetricsRecorder - take a look at the code in com.spotify.feline.FelineMetricsRecorder for more detail.

JUnit integration

Feline can also be used to detect blocking futures in your tests. We provide integration with Junit 4 and 5.

JUnit 4

When using JUnit 4, you can add automatic detection of blocking calls to all tests by adding a dependency on:

    <dependency>
      <groupId>com.spotify</groupId>
      <artifactId>futuristic-feline-junit4</artifactId>
      <version>$VERSION</version>
      <scope>test</scope>
    </dependency>

And registering FelineRunListener with your JUnit runs. One way of doing this is with the Maven Surefire plugin:

      <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.22.2</version>
        <configuration>
          <properties>
            <property>
              <name>listener</name>
              <value>com.spotify.feline.FelineRunListener</value>
            </property>
          </properties>
        </configuration>
      </plugin>

This will inject a RunListener that will fail tests on any blocking calls.

JUnit 5

When using JUnit 5 (not vintage), you can add automatic detection of blocking calls to all tests simply by adding a dependency on:

    <dependency>
      <groupId>com.spotify</groupId>
      <artifactId>futuristic-feline-junit5</artifactId>
      <version>$VERSION</version>
      <scope>test</scope>
    </dependency>

This will inject a TestExecutionListener that will fail tests on any blocking calls.

Ignoring blocking calls in tests

It's sometimes convenient to have blocking calls within your test methods themselves. In this case, you can ignore blocking calls by annotating your method:

  @Test
  @IgnoreBlocking
  public void ignoreBlockingJoin() {
    final CompletableFuture<Void> future = CompletableFuture.runAsync(RUNNABLE);

    // blocking, but works since we're ignoring blocking calls
    future.join();
  }

Note that this will still fail as @IgnoreBlocking only applies to the annotated method:

  @Test
  @IgnoreBlocking
  public void indirectIgnoreBlockingJoin() {
    blockingCall();
  }

  private void blockingCall() {
    final CompletableFuture<Void> future = CompletableFuture.runAsync(RUNNABLE);

    future.join();
  }

Development notes

Test failures when IntelliJ's debugger is attached

If you are working on futuristic-feline and have a need to attach IntelliJ's debugger to a test, you might find that all tests that depend on applying FelineTransformer are failing for mysterious reasons.

It seems that in some versions of IntelliJ, the debugger will attach an agent of its own to the Java process that it launches to run tests, which interferes with how Feline sets up its own agent.

This can be easily addressed by opening IntelliJ's settings and under Build, Execution, Deployment > Debugger > Async Stack Traces, uncheck the box for "Instrumenting Agent":

Screenshot of IntelliJ settings to disable

References:

Code of Conduct

This project adheres to the Open Code of Conduct. By participating, you are expected to honor this code.

futuristic-feline's People

Contributors

mattnworb avatar protocol7 avatar spkrka avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.