来自流的网络呼叫ID的RxJava缓存结果(Redis或类似的缓存解决方案)

时间:2015-12-08 14:19:04

标签: caching rx-java observable

我需要一些RxJava的帮助。我有一个昂贵的网络调用,它返回一个Observable(来自elasticsearch的广告流)。我想缓存每个发出项目(广告)的ID属性10分钟(在Redis中),以便后续10分钟内的后续调用使用Cache中的ID从Elasticsearch获取广告。

我已经获得了一些代码 - 这在某种程度上可以实现预期的结果,(归功于以下博客...... http://blog.danlew.net/2015/06/22/loading-data-from-multiple-sources-with-rxjava/

它可以缓存流中的每个发出项,我需要的是将流中这些项的所有ID缓存为1个缓存条目

到目前为止的代码https://github.com/tonymurphy/rxjava适用于任何感兴趣的人,

下面的代码段
@Component
public class CachingObservable {

    private final Logger logger = LoggerFactory.getLogger(CachingObservable.class);

    @Autowired
    private AdvertService advertService;

    // Each "network" response is different
    private Long requestNumber = 0L;

    public Observable<Advert> getAdverts(final String location) {

        Observable<Advert> memory = memory(location);
        Observable<Advert> network = network(location);

        Observable<Advert> networkWithSave = network.doOnNext(new Action1<Advert>() {
            @Override
            public void call(Advert advert) {
                List<Long> ids = new ArrayList<Long>();
                ids.add(advert.getId());
                advertService.cache(location, ids);
            }
        });

        // Retrieve the first source with data - concat checks in order
        Observable<Advert> source = Observable.concat(memory,
                networkWithSave)
                .first();

        return source;
    }

根据我的理解,concat方法对我的用例并不实用。我需要知道网络可观察性是否/何时完成,我需要返回广告ID列表,我需要将它们存储在缓存中。我可以订阅网络可观察 - 但我希望它是懒惰的 - 只有在缓存中找不到数据时才会调用。因此,以下更新的代码不起作用..任何赞赏的想法

public Observable<Advert> getAdverts(final String location) {

    Observable<Advert> memory = memory(location);
    Observable<Advert> network = network(location);

    Observable<Advert> networkWithSave = network.doOnNext(new Action1<Advert>() {
        @Override
        public void call(Advert advert) {
            List<Long> ids = new ArrayList<Long>();
            ids.add(advert.getId());
            advertService.cache(location, ids);
        }
    });

    // Retrieve the first source with data - concat checks in order
    Observable<Advert> source = Observable.concat(memory,
            networkWithSave)
            .first();

    Observable<List<Advert>> listObservable = networkWithSave.toList();
    final Func1<List<Advert>, List<Long>> transformer = new Func1<List<Advert>, List<Long>>() {
        @Override
        public List<Long> call(List<Advert> adverts) {
            List<Long> ids = new ArrayList<Long>();
            for (Advert advert : adverts) {
                ids.add(advert.getId());
            }
            return ids;
        }
    };

    listObservable.map(transformer).subscribe(new Action1<List<Long>>() {
        @Override
        public void call(List<Long> ids) {
            logger.info("ids {}", ids);
        }
    });

    return source;
}

2 个答案:

答案 0 :(得分:0)

我要做的是使用过滤器来确保不会发出缓存的旧内容,以便concat跳转到网络调用:

Stream imageStream = picture.GetImage();
using (var memoryStream = new MemoryStream())
{
    imageStream.CopyTo(memoryStream);
    byte[] buffer = memoryStream.ToArray();
    // this is the Base64 string you are looking for
    string base64String = Convert.ToBase64String(buffer);
}

答案 1 :(得分:0)

好的,我认为我有一个适合我的解决方案。我可能忽略了一些东西,但它应该很容易吗?

public Observable<Advert> getAdverts(final String location) {

    Observable<Advert> memory = memory(location);
    final Observable<Advert> network = network(location);

    final Func1<List<Advert>, List<Long>> advertToIdTransformer = convertAdvertsToIds();

    memory.isEmpty().subscribe(new Action1<Boolean>() {
        @Override
        public void call(Boolean aBoolean) {
            if (aBoolean.equals(Boolean.TRUE)) {
                Observable<List<Long>> listObservable = network.toList().map(advertToIdTransformer);
                listObservable.subscribe(new Action1<List<Long>>() {
                    @Override
                    public void call(List<Long> ids) {
                        logger.info("Caching ids {}", ids);
                        advertService.cache(location, ids);
                    }
                });
            }
        }
    });

    // Retrieve the first source with data - concat checks in order
    Observable<Advert> source = Observable.concat(memory,
            network)
            .first();


    return source;
}