@Async
  public void run(DendriteGraph graph, JobMetadata.Id jobId) {
    EigenvectorCentralityJob job =
        new EigenvectorCentralityJob(metaGraphService.getMetaGraph(), jobId, graph);

    job.run();
  }
  @PreAuthorize("hasPermission(#graphId, 'graph', 'admin')")
  @RequestMapping(
      value = "/api/graphs/{graphId}/analysis/faunus-degrees",
      method = RequestMethod.POST)
  public ResponseEntity<Map<String, Object>> startFaunusJob(@PathVariable String graphId)
      throws Exception {

    Map<String, Object> response = new HashMap<>();

    DendriteGraph graph = metaGraphService.getDendriteGraph(graphId);
    if (graph == null) {
      response.put("status", "error");
      response.put("msg", "missing graph metadata '" + graphId + "'");
      return new ResponseEntity<>(response, HttpStatus.NOT_FOUND);
    }

    MetaGraphTx tx = metaGraphService.newTransaction();

    GraphMetadata graphMetadata = tx.getGraph(graphId);
    if (graphMetadata == null) {
      response.put("status", "error");
      response.put("msg", "missing graph metadata '" + graphId + "'");
      tx.rollback();
      return new ResponseEntity<>(response, HttpStatus.NOT_FOUND);
    }

    ProjectMetadata projectMetadata = graphMetadata.getProject();
    if (projectMetadata == null) {
      response.put("status", "error");
      response.put("msg", "missing project metadata for graph '" + graphId + "'");
      tx.rollback();
      return new ResponseEntity<>(response, HttpStatus.NOT_FOUND);
    }

    JobMetadata jobMetadata = tx.createJob(projectMetadata);

    response.put("status", "ok");
    response.put("msg", "job submitted");
    response.put("jobId", jobMetadata.getId().toString());

    tx.commit();

    // We can't pass the values directly because they'll live in a separate thread.
    edgeDegreesService.faunusCountDegrees(graph, jobMetadata.getId());

    return new ResponseEntity<>(response, HttpStatus.OK);
  }