Netflix / Hystrix

Hystrix is a latency and fault tolerance library designed to isolate points of access to remote systems, services and 3rd party libraries, stop cascading failure and enable resilience in complex distributed systems where failure is inevitable.
24.12k stars 4.7k forks source link

Semaphore strategy fallback method Authentication issue #1949

Open aseemgoyal opened 5 years ago

aseemgoyal commented 5 years ago

Hi, i am using spring boot 1.5 and hystrix (spring-cloud-starter-hystrix). I am using semaphore isolation strategy, but still in the fallback method, Authentication is not available in the SecurityContext. However, according to the documentation, SecurityContext will be maintained with SEMAPHORE isolation. What should be done to fix this? Here is what i have tried :

    @CachePut(cacheNames = Constants.CACHE_NAME_ALL_COLLIBRA_ASSETS_BY_DOMAIN_ID_BACKUP, key = "#domainId")
    @HystrixCommand(fallbackMethod = "getAssetsFromBackup", commandKey = "getMetadataAssets", commandProperties = {
            @HystrixProperty(name = "execution.isolation.strategy", value = "SEMAPHORE")
    })
    public String getAssetsByDomain(String domainId) {
        String assets = null;
        try {
            Map<String, Object> queryParams = new HashMap<>();
            queryParams.put("domainId", domainId);
            queryParams.put("limit", Constants.COLLIBRA_GET_ALL_ASSETS_LIMIT);
            queryParams.put("offset", Constants.COLLIBRA_GET_ALL_ASSETS_OFFSET);
            ResponseEntity<String> response = collibraProxy.callCollibra(GET_ALL_ASSETS_ENDPOINT, HttpMethod.GET, null, queryParams);
            if (response.getStatusCode() == HttpStatus.OK) {
                assets = response.getBody();
            } else {
                throw new FGCollibException("Exception while getting OK response from Collibra: " + response.getStatusCode());
            }
        } catch (FGCollibException e) {
            logger.error("Error in getting assets from collibra for domainId {}", domainId, e);
            throw new FgException("Error getting response from collibra");
        }
        return assets;
    }

    public String getAssetsFromBackup(String domainId) {
        try {
            logger.info("Executing fallback logic for collibra backup");
            CacheEntry entry = cacheService.get(Constants.CACHE_NAME_ALL_COLLIBRA_ASSETS_BY_DOMAIN_ID_BACKUP, domainId);
            if (entry != null) {
                return (String) entry.getV();
            }
        } catch (Exception e) {
            logger.error("Error in getting assets from collibra backup for domainId {}", domainId, e);
        }
        return null;
    }

The collibraProxy.callCollibra(GET_ALL_ASSETS_ENDPOINT, HttpMethod.GET, null, queryParams); call timeouts and the fallback method getAssetsFromBackup method is called. However, it looses the context. image

Edit : I have tried using custom concurrency strategy, this doesn't work either. ConcurrencyStrategy:

    private HystrixConcurrencyStrategy existingConcurrencyStrategy;

    public SecurityContextConcurrencyStrategy(
            HystrixConcurrencyStrategy existingConcurrencyStrategy) {
        this.existingConcurrencyStrategy = existingConcurrencyStrategy;
    }

    @Override
    public BlockingQueue<Runnable> getBlockingQueue(int maxQueueSize) {
        return existingConcurrencyStrategy != null
                ? existingConcurrencyStrategy.getBlockingQueue(maxQueueSize)
                : super.getBlockingQueue(maxQueueSize);
    }

    @Override
    public <T> HystrixRequestVariable<T> getRequestVariable(
            HystrixRequestVariableLifecycle<T> rv) {
        return existingConcurrencyStrategy != null
                ? existingConcurrencyStrategy.getRequestVariable(rv)
                : super.getRequestVariable(rv);
    }

    @Override
    public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
                                            HystrixProperty<Integer> corePoolSize,
                                            HystrixProperty<Integer> maximumPoolSize,
                                            HystrixProperty<Integer> keepAliveTime, TimeUnit unit,
                                            BlockingQueue<Runnable> workQueue) {
        return existingConcurrencyStrategy != null
                ? existingConcurrencyStrategy.getThreadPool(threadPoolKey, corePoolSize,
                maximumPoolSize, keepAliveTime, unit, workQueue)
                : super.getThreadPool(threadPoolKey, corePoolSize, maximumPoolSize,
                keepAliveTime, unit, workQueue);
    }

    @Override
    public <T> Callable<T> wrapCallable(Callable<T> callable) {
        return existingConcurrencyStrategy != null
                ? existingConcurrencyStrategy
                .wrapCallable(new DelegatingSecurityContextCallable<T>(callable))
                : super.wrapCallable(new DelegatingSecurityContextCallable<T>(callable));
    }
}

Configuration:

@Configuration
public class HystrixContextAutoConfiguration {

    @Autowired(required = false)
    private List<HystrixCallableWrapper> wrappers = new ArrayList<>();
    @Autowired(required = false)
    private HystrixConcurrencyStrategy existingConcurrencyStrategy;

    @PostConstruct
    public void init() {
        HystrixPlugins.reset();
        // Keeps references of existing Hystrix plugins.
        HystrixEventNotifier eventNotifier = HystrixPlugins.getInstance()
                .getEventNotifier();
        HystrixMetricsPublisher metricsPublisher = HystrixPlugins.getInstance()
                .getMetricsPublisher();
        HystrixPropertiesStrategy propertiesStrategy = HystrixPlugins.getInstance()
                .getPropertiesStrategy();
        HystrixCommandExecutionHook commandExecutionHook = HystrixPlugins.getInstance()
                .getCommandExecutionHook();

        HystrixPlugins.reset();

        // Registers existing plugins excepts the Concurrent Strategy plugin.
        HystrixPlugins.getInstance().registerConcurrencyStrategy(
                new SecurityContextConcurrencyStrategy(existingConcurrencyStrategy));
        HystrixPlugins.getInstance().registerEventNotifier(eventNotifier);
        HystrixPlugins.getInstance().registerMetricsPublisher(metricsPublisher);
        HystrixPlugins.getInstance().registerPropertiesStrategy(propertiesStrategy);
        HystrixPlugins.getInstance().registerCommandExecutionHook(commandExecutionHook);
    }

The breakpoint does not hit wrapCallable, i assume the strategy is not registered?

aseemgoyal commented 5 years ago

Hi, i am waiting for some reply.

rs-ajadhav commented 3 years ago

I am facing a similar issue. Can someone please help us on this