List of usage examples for com.google.common.util.concurrent Futures catchingAsync
@GwtIncompatible("AVAILABLE but requires exceptionType to be Throwable.class") public static <V, X extends Throwable> ListenableFuture<V> catchingAsync(ListenableFuture<? extends V> input, Class<X> exceptionType, AsyncFunction<? super X, ? extends V> fallback)
From source file:io.v.todos.persistence.syncbase.SyncbaseMain.java
private ListenableFuture<SyncgroupSpec> joinWithRetry(final Id listId, final int numTimes, final int limit) { final String debugString = (numTimes + 1) + "/" + limit + " for: " + listId; Log.d(TAG, "Join attempt " + debugString); if (numTimes + 1 == limit) { // final attempt! return joinListSyncgroup(listId); }/*from w w w . j a v a 2 s . co m*/ // Note: This can be easily converted to exponential backoff. final long startTime = System.currentTimeMillis(); return Futures.catchingAsync(joinListSyncgroup(listId), SyncgroupJoinFailedException.class, new AsyncFunction<SyncgroupJoinFailedException, SyncgroupSpec>() { public ListenableFuture<SyncgroupSpec> apply(@Nullable SyncgroupJoinFailedException input) { long failTime = System.currentTimeMillis(); long delay = Math.max(0, MIN_RETRY_DELAY + startTime - failTime); Log.d(TAG, "Join failed. Sleeping " + debugString + " with delay " + delay); return sExecutor.schedule(new Callable<SyncgroupSpec>() { @Override public SyncgroupSpec call() { Log.d(TAG, "Sleep done. Retry " + debugString); // If this errors, then we will not get another chance to // see this syncgroup until the app is restarted. try { return joinWithRetry(listId, numTimes + 1, limit).get(); } catch (InterruptedException | ExecutionException e) { return null; } } }, delay, TimeUnit.MILLISECONDS); } }); }
From source file:io.vitess.client.grpc.GrpcClient.java
@Override public ListenableFuture<BeginResponse> begin(Context ctx, BeginRequest request) throws SQLException { return Futures.catchingAsync(getFutureStub(ctx).begin(request), Exception.class, new ExceptionConverter<BeginResponse>()); }
From source file:io.vitess.client.grpc.GrpcClient.java
@Override public ListenableFuture<CommitResponse> commit(Context ctx, CommitRequest request) throws SQLException { return Futures.catchingAsync(getFutureStub(ctx).commit(request), Exception.class, new ExceptionConverter<CommitResponse>()); }
From source file:io.vitess.client.grpc.GrpcClient.java
@Override public ListenableFuture<RollbackResponse> rollback(Context ctx, RollbackRequest request) throws SQLException { return Futures.catchingAsync(getFutureStub(ctx).rollback(request), Exception.class, new ExceptionConverter<RollbackResponse>()); }
From source file:io.vitess.client.grpc.GrpcClient.java
@Override public ListenableFuture<SplitQueryResponse> splitQuery(Context ctx, SplitQueryRequest request) throws SQLException { return Futures.catchingAsync(getFutureStub(ctx).splitQuery(request), Exception.class, new ExceptionConverter<SplitQueryResponse>()); }
From source file:io.vitess.client.grpc.GrpcClient.java
@Override public ListenableFuture<GetSrvKeyspaceResponse> getSrvKeyspace(Context ctx, GetSrvKeyspaceRequest request) throws SQLException { return Futures.catchingAsync(getFutureStub(ctx).getSrvKeyspace(request), Exception.class, new ExceptionConverter<GetSrvKeyspaceResponse>()); }
From source file:com.facebook.buck.rules.CachingBuildRuleBuilder.java
ListenableFuture<BuildResult> build() { final AtomicReference<Long> outputSize = Atomics.newReference(); ListenableFuture<List<BuildResult>> depResults = Futures.immediateFuture(Collections.emptyList()); // If we're performing a deep build, guarantee that all dependencies will *always* get // materialized locally if (buildMode == CachingBuildEngine.BuildMode.DEEP || buildMode == CachingBuildEngine.BuildMode.POPULATE_FROM_REMOTE_CACHE) { depResults = buildRuleBuilderDelegate.getDepResults(rule, buildContext, executionContext); }//w ww . ja v a 2 s. c o m ListenableFuture<BuildResult> buildResult = Futures.transformAsync(depResults, input -> buildOrFetchFromCache(), serviceByAdjustingDefaultWeightsTo(CachingBuildEngine.SCHEDULING_MORE_WORK_RESOURCE_AMOUNTS)); // Check immediately (without posting a new task) for a failure so that we can short-circuit // pending work. Use .catchingAsync() instead of .catching() so that we can propagate unchecked // exceptions. buildResult = Futures.catchingAsync(buildResult, Throwable.class, throwable -> { Preconditions.checkNotNull(throwable); buildRuleBuilderDelegate.setFirstFailure(throwable); Throwables.throwIfInstanceOf(throwable, Exception.class); throw new RuntimeException(throwable); }); buildResult = Futures.transform(buildResult, (result) -> { buildRuleBuilderDelegate.markRuleAsUsed(rule, buildContext.getEventBus()); return result; }, MoreExecutors.directExecutor()); // Setup a callback to handle either the cached or built locally cases. AsyncFunction<BuildResult, BuildResult> callback = input -> { // If we weren't successful, exit now. if (input.getStatus() != BuildRuleStatus.SUCCESS) { return Futures.immediateFuture(input); } try (Scope scope = LeafEvents.scope(buildContext.getEventBus(), "finalizing_build_rule")) { // We shouldn't see any build fail result at this point. BuildRuleSuccessType success = Preconditions.checkNotNull(input.getSuccess()); // If we didn't build the rule locally, reload the recorded paths from the build // metadata. if (success != BuildRuleSuccessType.BUILT_LOCALLY) { try { for (String str : onDiskBuildInfo.getValuesOrThrow(BuildInfo.MetadataKey.RECORDED_PATHS)) { buildInfoRecorder.recordArtifact(Paths.get(str)); } } catch (IOException e) { LOG.error(e, "Failed to read RECORDED_PATHS for %s", rule); throw e; } } // Try get the output size now that all outputs have been recorded. if (success == BuildRuleSuccessType.BUILT_LOCALLY) { outputSize.set(buildInfoRecorder.getOutputSize()); } // If the success type means the rule has potentially changed it's outputs... if (success.outputsHaveChanged()) { // The build has succeeded, whether we've fetched from cache, or built locally. // So run the post-build steps. if (rule instanceof HasPostBuildSteps) { executePostBuildSteps( ((HasPostBuildSteps) rule).getPostBuildSteps(buildContext.getBuildContext())); } // Invalidate any cached hashes for the output paths, since we've updated them. for (Path path : buildInfoRecorder.getRecordedPaths()) { fileHashCache.invalidate(rule.getProjectFilesystem().resolve(path)); } } if (SupportsInputBasedRuleKey.isSupported(rule) && success == BuildRuleSuccessType.BUILT_LOCALLY && !buildInfoRecorder.getBuildMetadataFor(BuildInfo.MetadataKey.INPUT_BASED_RULE_KEY) .isPresent()) { // Doing this here is probably not strictly necessary, however in the case of // pipelined rules built locally we will never do an input-based cache check. // That check would have written the key to metadata, and there are some asserts // during cache upload that try to ensure they are present. Optional<RuleKey> inputRuleKey = calculateInputBasedRuleKey(buildContext.getEventBus()); if (inputRuleKey.isPresent()) { buildInfoRecorder.addBuildMetadata(BuildInfo.MetadataKey.INPUT_BASED_RULE_KEY, inputRuleKey.get().toString()); } } // If this rule uses dep files and we built locally, make sure we store the new dep file // list and re-calculate the dep file rule key. if (useDependencyFileRuleKey() && success == BuildRuleSuccessType.BUILT_LOCALLY) { // Query the rule for the actual inputs it used. ImmutableList<SourcePath> inputs = ((SupportsDependencyFileRuleKey) rule) .getInputsAfterBuildingLocally(buildContext.getBuildContext(), executionContext.getCellPathResolver()); // Record the inputs into our metadata for next time. // TODO(#9117006): We don't support a way to serlialize `SourcePath`s to the cache, // so need to use DependencyFileEntry's instead and recover them on deserialization. ImmutableList<String> inputStrings = inputs.stream() .map(inputString -> DependencyFileEntry.fromSourcePath(inputString, pathResolver)) .map(MoreFunctions.toJsonFunction()).collect(MoreCollectors.toImmutableList()); buildInfoRecorder.addMetadata(BuildInfo.MetadataKey.DEP_FILE, inputStrings); // Re-calculate and store the depfile rule key for next time. Optional<RuleKeyAndInputs> depFileRuleKeyAndInputs = calculateDepFileRuleKey( Optional.of(inputStrings), /* allowMissingInputs */ false); if (depFileRuleKeyAndInputs.isPresent()) { RuleKey depFileRuleKey = depFileRuleKeyAndInputs.get().getRuleKey(); buildInfoRecorder.addBuildMetadata(BuildInfo.MetadataKey.DEP_FILE_RULE_KEY, depFileRuleKey.toString()); // Push an updated manifest to the cache. if (useManifestCaching()) { Optional<RuleKeyAndInputs> manifestKey = calculateManifestKey( buildContext.getEventBus()); if (manifestKey.isPresent()) { buildInfoRecorder.addBuildMetadata(BuildInfo.MetadataKey.MANIFEST_KEY, manifestKey.get().getRuleKey().toString()); updateAndStoreManifest(depFileRuleKeyAndInputs.get().getRuleKey(), depFileRuleKeyAndInputs.get().getInputs(), manifestKey.get(), buildContext.getArtifactCache()); } } } } // If this rule was built locally, grab and record the output hashes in the build // metadata so that cache hits avoid re-hashing file contents. Since we use output // hashes for input-based rule keys and for detecting non-determinism, we would spend // a lot of time re-hashing output paths -- potentially in serialized in a single step. // So, do the hashing here to distribute the workload across several threads and cache // the results. // // Also, since hashing outputs can potentially be expensive, we avoid doing this for // rules that are marked as uncacheable. The rationale here is that they are likely not // cached due to the sheer size which would be costly to hash or builtin non-determinism // in the rule which somewhat defeats the purpose of logging the hash. if (success == BuildRuleSuccessType.BUILT_LOCALLY && shouldUploadToCache(success, Preconditions.checkNotNull(outputSize.get()))) { ImmutableSortedMap.Builder<String, String> outputHashes = ImmutableSortedMap.naturalOrder(); for (Path path : buildInfoRecorder.getOutputPaths()) { outputHashes.put(path.toString(), fileHashCache.get(rule.getProjectFilesystem().resolve(path)).toString()); } buildInfoRecorder.addBuildMetadata(BuildInfo.MetadataKey.RECORDED_PATH_HASHES, outputHashes.build()); } // If this rule was fetched from cache, seed the file hash cache with the recorded // output hashes from the build metadata. Since outputs which have been changed have // already been invalidated above, this is purely a best-effort optimization -- if the // the output hashes weren't recorded in the cache we do nothing. if (success != BuildRuleSuccessType.BUILT_LOCALLY && success.outputsHaveChanged()) { Optional<ImmutableMap<String, String>> hashes = onDiskBuildInfo .getBuildMap(BuildInfo.MetadataKey.RECORDED_PATH_HASHES); // We only seed after first verifying the recorded path hashes. This prevents the // optimization, but is useful to keep in place for a while to verify this optimization // is causing issues. if (hashes.isPresent() && verifyRecordedPathHashes(rule.getBuildTarget(), rule.getProjectFilesystem(), hashes.get())) { // Seed the cache with the hashes. for (Map.Entry<String, String> ent : hashes.get().entrySet()) { Path path = rule.getProjectFilesystem().getPath(ent.getKey()); HashCode hashCode = HashCode.fromString(ent.getValue()); fileHashCache.set(rule.getProjectFilesystem().resolve(path), hashCode); } } } // Make sure the origin field is filled in. BuildId buildId = buildContext.getBuildId(); if (success == BuildRuleSuccessType.BUILT_LOCALLY) { buildInfoRecorder.addBuildMetadata(BuildInfo.MetadataKey.ORIGIN_BUILD_ID, buildId.toString()); } else if (success.outputsHaveChanged()) { Preconditions.checkState( buildInfoRecorder.getBuildMetadataFor(BuildInfo.MetadataKey.ORIGIN_BUILD_ID) .isPresent(), "Cache hits must populate the %s field (%s)", BuildInfo.MetadataKey.ORIGIN_BUILD_ID, success); } // Make sure that all of the local files have the same values they would as if the // rule had been built locally. buildInfoRecorder.addBuildMetadata(BuildInfo.MetadataKey.TARGET, rule.getBuildTarget().toString()); buildInfoRecorder.addMetadata(BuildInfo.MetadataKey.RECORDED_PATHS, buildInfoRecorder.getRecordedPaths().stream().map(Object::toString) .collect(MoreCollectors.toImmutableList())); if (success.shouldWriteRecordedMetadataToDiskAfterBuilding()) { try { boolean clearExistingMetadata = success.shouldClearAndOverwriteMetadataOnDisk(); buildInfoRecorder.writeMetadataToDisk(clearExistingMetadata); } catch (IOException e) { throw new IOException(String.format("Failed to write metadata to disk for %s.", rule), e); } } // Give the rule a chance to populate its internal data structures now that all of // the files should be in a valid state. try { if (rule instanceof InitializableFromDisk) { doInitializeFromDisk((InitializableFromDisk<?>) rule); } } catch (IOException e) { throw new IOException( String.format("Error initializing %s from disk: %s.", rule, e.getMessage()), e); } } return Futures.immediateFuture(input); }; buildResult = Futures.transformAsync(buildResult, ruleAsyncFunction(buildContext.getEventBus(), callback), serviceByAdjustingDefaultWeightsTo(CachingBuildEngine.RULE_KEY_COMPUTATION_RESOURCE_AMOUNTS)); buildResult = Futures.catchingAsync(buildResult, Throwable.class, thrown -> { LOG.debug(thrown, "Building rule [%s] failed.", rule.getBuildTarget()); if (consoleLogBuildFailuresInline) { buildContext.getEventBus().post(ConsoleEvent.severe(getErrorMessageIncludingBuildRule(thrown))); } thrown = maybeAttachBuildRuleNameToException(thrown); recordFailureAndCleanUp(thrown); return Futures.immediateFuture(BuildResult.failure(rule, thrown)); }); // Do things that need to happen after either success or failure, but don't block the dependents // while doing so: buildRuleBuilderDelegate .addAsyncCallback(MoreFutures.addListenableCallback(buildResult, new FutureCallback<BuildResult>() { private void uploadToCache(BuildRuleSuccessType success) { // Collect up all the rule keys we have index the artifact in the cache with. Set<RuleKey> ruleKeys = new HashSet<>(); // If the rule key has changed (and is not already in the cache), we need to push // the artifact to cache using the new key. ruleKeys.add(ruleKeyFactories.getDefaultRuleKeyFactory().build(rule)); // If the input-based rule key has changed, we need to push the artifact to cache // using the new key. if (SupportsInputBasedRuleKey.isSupported(rule)) { Optional<RuleKey> calculatedRuleKey = calculateInputBasedRuleKey( buildContext.getEventBus()); Optional<RuleKey> onDiskRuleKey = onDiskBuildInfo .getRuleKey(BuildInfo.MetadataKey.INPUT_BASED_RULE_KEY); Optional<RuleKey> metaDataRuleKey = buildInfoRecorder .getBuildMetadataFor(BuildInfo.MetadataKey.INPUT_BASED_RULE_KEY) .map(RuleKey::new); Preconditions.checkState(calculatedRuleKey.equals(onDiskRuleKey), "%s (%s): %s: invalid on-disk input-based rule key: %s != %s", rule.getBuildTarget(), rule.getType(), success, calculatedRuleKey, onDiskRuleKey); Preconditions.checkState(calculatedRuleKey.equals(metaDataRuleKey), "%s: %s: invalid meta-data input-based rule key: %s != %s", rule.getBuildTarget(), success, calculatedRuleKey, metaDataRuleKey); if (calculatedRuleKey.isPresent()) { ruleKeys.add(calculatedRuleKey.get()); } } // If the manifest-based rule key has changed, we need to push the artifact to cache // using the new key. if (useManifestCaching()) { Optional<RuleKey> onDiskRuleKey = onDiskBuildInfo .getRuleKey(BuildInfo.MetadataKey.DEP_FILE_RULE_KEY); Optional<RuleKey> metaDataRuleKey = buildInfoRecorder .getBuildMetadataFor(BuildInfo.MetadataKey.DEP_FILE_RULE_KEY).map(RuleKey::new); Preconditions.checkState(onDiskRuleKey.equals(metaDataRuleKey), "%s: %s: inconsistent meta-data and on-disk dep-file rule key: %s != %s", rule.getBuildTarget(), success, onDiskRuleKey, metaDataRuleKey); if (onDiskRuleKey.isPresent()) { ruleKeys.add(onDiskRuleKey.get()); } } // Do the actual upload. try { // Verify that the recorded path hashes are accurate. Optional<String> recordedPathHashes = buildInfoRecorder .getBuildMetadataFor(BuildInfo.MetadataKey.RECORDED_PATH_HASHES); if (recordedPathHashes.isPresent() && !verifyRecordedPathHashes(rule.getBuildTarget(), rule.getProjectFilesystem(), recordedPathHashes.get())) { return; } // Push to cache. buildInfoRecorder.performUploadToArtifactCache(ImmutableSet.copyOf(ruleKeys), buildContext.getArtifactCache(), buildContext.getEventBus()); } catch (Throwable t) { buildContext.getEventBus().post( ThrowableConsoleEvent.create(t, "Error uploading to cache for %s.", rule)); } } private void handleResult(BuildResult input) { Optional<Long> outputSize = Optional.empty(); Optional<HashCode> outputHash = Optional.empty(); Optional<BuildRuleSuccessType> successType = Optional.empty(); boolean shouldUploadToCache = false; BuildRuleEvent.Resumed resumedEvent = BuildRuleEvent.resumed(rule, buildRuleDurationTracker, ruleKeyFactories.getDefaultRuleKeyFactory()); LOG.verbose(resumedEvent.toString()); buildContext.getEventBus().post(resumedEvent); if (input.getStatus() == BuildRuleStatus.SUCCESS) { BuildRuleSuccessType success = Preconditions.checkNotNull(input.getSuccess()); successType = Optional.of(success); // Try get the output size. if (success == BuildRuleSuccessType.BUILT_LOCALLY || success.shouldUploadResultingArtifact()) { try { outputSize = Optional.of(buildInfoRecorder.getOutputSize()); } catch (IOException e) { buildContext.getEventBus().post(ThrowableConsoleEvent.create(e, "Error getting output size for %s.", rule)); } } // Compute it's output hash for logging/tracing purposes, as this artifact will // be consumed by other builds. if (outputSize.isPresent() && shouldHashOutputs(success, outputSize.get())) { try { outputHash = Optional.of(buildInfoRecorder.getOutputHash(fileHashCache)); } catch (IOException e) { buildContext.getEventBus().post(ThrowableConsoleEvent.create(e, "Error getting output hash for %s.", rule)); } } // Determine if this is rule is cacheable. shouldUploadToCache = outputSize.isPresent() && shouldUploadToCache(success, outputSize.get()); // Upload it to the cache. if (shouldUploadToCache) { uploadToCache(success); } } boolean failureOrBuiltLocally = input.getStatus() == BuildRuleStatus.FAIL || input.getSuccess() == BuildRuleSuccessType.BUILT_LOCALLY; // Log the result to the event bus. BuildRuleEvent.Finished finished = BuildRuleEvent.finished(resumedEvent, getBuildRuleKeys(), input.getStatus(), input.getCacheResult(), onDiskBuildInfo.getBuildValue(BuildInfo.MetadataKey.ORIGIN_BUILD_ID) .map(BuildId::new), successType, shouldUploadToCache, outputHash, outputSize, getBuildRuleDiagnosticData(failureOrBuiltLocally)); LOG.verbose(finished.toString()); buildContext.getEventBus().post(finished); } @Override public void onSuccess(BuildResult input) { handleResult(input); // Reset interrupted flag once failure has been recorded. if (input.getFailure() instanceof InterruptedException) { Threads.interruptCurrentThread(); } } @Override public void onFailure(@Nonnull Throwable thrown) { throw new AssertionError("Dead code"); } }, serviceByAdjustingDefaultWeightsTo(CachingBuildEngine.RULE_KEY_COMPUTATION_RESOURCE_AMOUNTS))); return buildResult; }
From source file:com.facebook.buck.core.build.engine.impl.CachingBuildRuleBuilder.java
ListenableFuture<BuildResult> build() { AtomicReference<Long> outputSize = Atomics.newReference(); ListenableFuture<List<BuildResult>> depResults = Futures.immediateFuture(Collections.emptyList()); // If we're performing a deep build, guarantee that all dependencies will *always* get // materialized locally if (buildMode == BuildType.DEEP || buildMode == BuildType.POPULATE_FROM_REMOTE_CACHE) { depResults = buildRuleBuilderDelegate.getDepResults(rule, executionContext); }/*from w ww . j a v a 2s. c o m*/ ListenableFuture<BuildResult> buildResult = Futures.transformAsync(depResults, input -> buildOrFetchFromCache(), serviceByAdjustingDefaultWeightsTo(CachingBuildEngine.SCHEDULING_MORE_WORK_RESOURCE_AMOUNTS)); // Check immediately (without posting a new task) for a failure so that we can short-circuit // pending work. Use .catchingAsync() instead of .catching() so that we can propagate unchecked // exceptions. buildResult = Futures.catchingAsync(buildResult, Throwable.class, throwable -> { Objects.requireNonNull(throwable); BuildRuleFailedException failedException = getFailedException(throwable); buildRuleBuilderDelegate.setFirstFailure(failedException); throw failedException; }); buildResult = Futures.transform(buildResult, (result) -> { buildRuleBuilderDelegate.markRuleAsUsed(rule, eventBus); return result; }, MoreExecutors.directExecutor()); buildResult = Futures.transformAsync(buildResult, ruleAsyncFunction(result -> finalizeBuildRule(result, outputSize)), serviceByAdjustingDefaultWeightsTo(CachingBuildEngine.RULE_KEY_COMPUTATION_RESOURCE_AMOUNTS)); buildResult = Futures.catchingAsync(buildResult, Throwable.class, thrown -> { String message = String.format("Building rule [%s] failed.", rule.getBuildTarget()); BuildRuleFailedException failedException = getFailedException(thrown); LOG.debug(failedException, message); if (consoleLogBuildFailuresInline) { // TODO(cjhopman): This probably shouldn't be a thing. Why can't we just rely on the // propagated failure being printed? eventBus.post(ConsoleEvent.severe(message)); } recordFailureAndCleanUp(failedException); return Futures.immediateFuture(failure(thrown)); }); // Do things that need to happen after either success or failure, but don't block the dependents // while doing so: buildRuleBuilderDelegate .addAsyncCallback(MoreFutures.addListenableCallback(buildResult, new FutureCallback<BuildResult>() { @Override public void onSuccess(BuildResult input) { handleResult(input); // Reset interrupted flag once failure has been recorded. if (!input.isSuccess() && input.getFailure() instanceof InterruptedException) { Threads.interruptCurrentThread(); } } @Override public void onFailure(@Nonnull Throwable thrown) { throw new AssertionError("Dead code", thrown); } }, serviceByAdjustingDefaultWeightsTo(CachingBuildEngine.RULE_KEY_COMPUTATION_RESOURCE_AMOUNTS))); return buildResult; }