Quantcast
Channel: Active questions tagged redis+java - Stack Overflow
Viewing all 2217 articles
Browse latest View live

Redis on Java Connection Pool - number of connections keep increasing

$
0
0

I am trying to configure the Jedis connection pool. Below are my settings:

jedisConFactory.getPoolConfig().setMaxTotal(30);
jedisConFactory.getPoolConfig().setMaxIdle(10);
jedisConFactory.getPoolConfig().setMinIdle(5);
jedisConFactory.getPoolConfig().setBlockWhenExhausted(true);
jedisConFactory.setTimeout(10000); // enable this causing exception 

I have set setMaxTotal to a fixed value in the above code, however the number of connections on Redis server still keeps increasing.

I expect the Pool is able to maintain the number of connections on a right amounts and could not exceed the MaxTotal value.

My question is:

Immediately after a pool closes a connection, the Redis server will also close this connection immediately or will it still hold the connection for some time? Which factor controls this feature?

Also if I enable jedisConFactory.setTimeout(10000), sometimes it throws an exception:

JedisConnectionException: Unexpected end of stream....


Mock redis template

$
0
0

I am facing a issue in mock redis template. Can any one help me to write unit test for below class.

@Repository
public class CasheRepo {

    @Autowired
    private RedisTemplate<String, Object> template;

    public Object getObject(final String key) {
    return template.opsForValue().get(key);
    }
}

And below is unit test class. But it is not working. It shows null point exceptions

@RunWith(MockitoJUnitRunner.class)
public class CashRepoTest {
    @InjectMocks
    private CasheRepo casheRepo = new CasheRepo();

    private @Mock RedisConnection redisConnectionMock;
    private @Mock RedisConnectionFactory redisConnectionFactoryMock;

    private RedisTemplate redisTemplate;

    @Before
    public void setUp() {   Mockito.when(redisConnectionFactoryMock.getConnection()).thenReturn(redisConnectionMock);   
    redisTemplate = new RedisTemplate();
    redisTemplate.setConnectionFactory(redisConnectionFactoryMock);
    redisTemplate.afterPropertiesSet();
    }

    @Test
    public void getObjectTest() {
    Mockito.doNothing().when(redisTemplate).opsForValue().set("spring", "data");
    redisTemplate.afterPropertiesSet();  
    System.out.println(redisTemplate.opsForValue().get("spring"));   
    }    
}

Redis - how to deserialize a Map cached in redis?

$
0
0

I am trying to move some user settings to a cache in Redis. In the current solution, the settings are cached in the app memory as:

    private final Cache<Integer, Map<Integer, Object>> userSettingsCache;

The key here is of course the userId, while the value is a map of where Integer describes an index of setting-type and Object can be one of different setting types - CountrySettings, LanguageSettings etc.

I would like to move this cache to Redis. However I encounter a problem when trying to load the cached values back from Redis. The problem is with the deserialization, here is the error message:

org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [byte[]] to type [com.example.demo.CountrySettings]

This is the class describing the settings I save in Redis:

@RedisHash("UserSettings")
public class UserSettings implements Serializable {
    @Id
    private String id;
    private Map<Integer, Object> map;
}

the code I use for saving the object:

        Map<Integer, Object> map = new HashMap<>();
        map.put(1, new CountrySettings(1L, "UK", "United Kingdom"));
        map.put(2, new LanguageSettings(3L, "English"));
        settingsRedisRepository.save(new UserSettings("someId1", map));

the code i use for retrieving the object:

settingsRedisRepository.findById("someId1").orElse(null);

I use spring-data-redis.

I tried using different custom deserializers between byte[] and Object, but none of it worked. Has anyone had this problem?

correct way to establish a redis connection with lettuce in java 8

$
0
0

I am trying to build a Denodo java stored procedure that communicates with redis via lettuce.

I am using the Denodo 4e eclipse extension and oxygen as recommended by Denodo.

I am clearly missing something because all of the documentation indicates that both

int port = 6379;
String host = "127.0.0.1";
RedisURi uri = RedisURI.Builder.redis(host,port).withDatabase(1).build();
RedisClient client = RedisClient.create(uri);

and

RedisClient client = RedisClient.create("redis://localhost:6379");

are throwing errors that are obscured by the debugging method all i know is that in the first instance the builder fails and in the second the client fails.

When I invoke the redis-cli i see that redis is running at 127.0.0.1:6379> and am able to get the test keys I have set.

user@system:~$ redis-cli
127.0.0.1:6379> get datum1
"datum2"

I am using a default redis.conf and running eclipse, denodo, and redis on the same machine.

Bind in redis.conf is 127.0.0.1 ::1 timeout is disabled (0)

I don't normally develop in Java so I'm hoping I am clearly doing something wrong rather than having to actually do this in a non-denodo project and sort out proper builds and debugging.

Java Lettuce Reactive Pattern - Catch Errors?

$
0
0

I'm trying to use lettuce instead of Jedis for it's reactive pattern. Jedis can block my vertx eventloop and instead of making it a blocking operation I'd rather have it be reactive.

I can successfully fetch items from redis using lettuce but I haven't figured out how to handle exceptions. As an example-

// Attempt A: Is the error in otherstuff?
redis.get(cacheKey).handle((response, otherstuff) -> {
            ...
        }).subscribe();

// Attempt B: Do I add a doOnError?
redis.get(cacheKey).handle((response, otherstuff) -> {
            ...
        }).doOnError((error) -> {
            logger.error(err);
        }).subscribe();

// Attempt C: Do I add my callbacks to subscribe?
redis.get(cacheKey).subscribe((response) -> {
            ...
        }, (err) -> {
            logger.error(err);
        });

The first confusion I have is how many ways I can do the same thing. I've found multiple ways to actually get a value, but I've found no way to catch an error. The cache key it's pulling from does not exist, my assumption is that an error would be thrown somewhere.

How do I catch lettuce errors?

Jedis - Missing HostPort class for simple program

$
0
0

I'm viewing RedisLab first course for Java developer,

In Hello World program they are using HostPort which isn't found in jedis:

Jedis jedis = new Jedis(HostPort.getRedisHost(), HostPort.getRedisPort());

What is HostPort class and why I can't find it?

There's HostAndPort, but it doesn't have those methods or similar getPort static methods

what's the difference between spring intergration redis and spring data redis?

$
0
0

what's the difference between spring intergration redis and spring data redis? I am a little confused about this. What's the relationship between them?

How to use FLUSHDB ASYNC with RedisTemplate?

$
0
0

Redis 4.0.0+ support flushdb async, but i can't find it on RedisServerCommands, is there any way to use flushdb async?


Spring Filter - cycle life for HttpSession with Bean Scoped session - do not persist properties into session

$
0
0

i have a probleme with httpSession and spring redis implementation. I have declare a filter who have one job. Catch a request param and set it into session. This attribute is use later for call an external api.

My implementation :

i use spring-boot

i use a JedisConnectionFactory for persist my session into reddis.

<dependency>
  <groupId>org.springframework.session</groupId>
  <artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
  <exclusions>
    <exclusion>
      <groupId>io.lettuce</groupId>
      <artifactId>lettuce-core</artifactId>
    </exclusion>
  </exclusions>
</dependency>
<dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
</dependency>

have declare use store-type redis to spring-boot

session:
    store-type: redis
    timeout: 900s

  redis:
    host: redis
    port: 6379

now my filter

@Component
@Slf4j
@Order(1)
public class MyCustomFilter implements Filter {

  @Resource
  private SessionHelper sessionHelper;

  @Override
  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

    HttpServletRequest request = (HttpServletRequest) servletRequest;

    // retrieve site from request attribute
    final String site = request.getParameter("site");

    // persiste site into session with a bean scoped SESSION
    sessionHelper.saveSite(site);

    filterChain.doFilter(request, response);
  }

}

my sessionHelper

@Component
@Slf4j
@Scope(value = SCOPE_SESSION, proxyMode = TARGET_CLASS)
public class SessionHelper implements Serializable {

  @Resource
  private HttpSession httpSession;

  public void saveSite(String site) {
    httpSession.setAttribute("site", site);
  }

  public String getSite(String site) {
    return (String) httpSession.getAttribute("site");
  }

}

my service who need to retrieve site from session

@Slf4j
@Component
public class MyFacade {

  @Resource
  private SessionHelper sessionHelper;

  public void myMethod() {
    log.debug(sessionHelper.getSite());
  }

}

result, my facade log always a null. So i don't understand why. My filter set this variable into session.

i have try to log sessionId for the moment when variable is set and when she is get. sessionId is different... and i don't understand why.

if someone has a clue for me...

thx

Redis with Springboot throws : No Capable converter found

$
0
0

I am trying to use Redis in a spring boot application as a cache. Below is how i am trying to use.

RedisEntity.Java

@Getter
@Setter
@RedisHash
public class RedisEntity {
    @Id
    private RequestObject requestObject;
    private ResponseObject responseObject;

}

Repository for Redis:

public interface RedisEntityRepository extends CrudRepository<RedisEntity, RequestObject> {

}

In Service Class:

@Autowired
RedisEntityRepository redisEntityRepository;

redisEntityRepository.save(requestObject);

I am getting the below exception while trying to save in the cache:

No converter found capable of converting from type [Package.request.RequestObject] to type [byte[]]

I am not sure whats causing the issue. Below is the Redis configuration i have:

@Configuration
public class RedisCache extends CachingConfigurerSupport {


    private long timeoutSeconds=200l;

    private long cacheDuration=2l;

    public Map<String, Long> getCacheExpiration() {
        Map<String, Long> cacheExpiration = new HashMap<>();
        cacheExpiration.put("object", TimeUnit.DAYS.toSeconds(cacheDuration));
        cacheExpiration.put("object1", TimeUnit.DAYS.toSeconds(cacheDuration));
        return cacheExpiration;
    }

    private static RedisCacheConfiguration createCacheConfiguration(long timeoutInSeconds) {
        return RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(timeoutInSeconds));
    }

    @Bean
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory cf) {
        RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(cf);
        return redisTemplate;
    }

    @Bean
    public RedisCacheConfiguration cacheConfiguration() {
        return createCacheConfiguration(timeoutSeconds);
    }

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        Map<String, RedisCacheConfiguration> cacheConfigurations = new HashMap<>();

        for (Entry<String, Long> cacheNameAndTimeout : getCacheExpiration().entrySet()) {
            cacheConfigurations.put(cacheNameAndTimeout.getKey(), createCacheConfiguration(cacheNameAndTimeout.getValue()));
        }

        return RedisCacheManager
                .builder(redisConnectionFactory)
                .cacheDefaults(cacheConfiguration())
                .withInitialCacheConfigurations(cacheConfigurations).build();
    }
}

Any suggestions are highly appreciated and will be helpful!

spring-data-redis cacheNames don't work if key-prefix is present

$
0
0

Assuming I have spring-data-redis application with the following method:

@Cacheable(
    value = "cacheName",
    key = "T(java.lang.String).format('tiles:%s', #categories.hashCode())")
public List<Tile> findAll(Set<String> categories) {
    return findAllByCategories(categories);
}

The entries saved to Redis as following:

cacheName::tiles:253903999

Now I can evict this cache from another method:

@CacheEvict(value = "cacheName", allEntries = true)
public Optional<Tile> save(Tile entity) {
    return super.save(entity);
}

And everything works as expected.

But setting property spring.cache.redis.key-prefix=prefix: gives me the following entry in Redis:

prefix:tiles:253903999

Cache cannot be evicted now since there are no information about cacheName.

Why should not it create the following entry:

cacheName::prefix:tiles:253903999

Is it possible to fix this? Why does spring-data-redis work that way?

Spring Data Redis Expire Key

$
0
0

I have a One Spring Hibernate Application. In my application, Recently i am implemented Spring data Redis.

spring-servlet.xml
<!-- redis connection factory -->
<bean id="jedisConnFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:use-pool="true"/>

<!-- redis template definition -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" 
    p:connection-factory-ref="jedisConnFactory"/>

And this redisTemplate use in my ServiceImpl class.

RedisServiceImpl

@Autowired
private RedisTemplate<String, T> redisTemplate;

public RedisTemplate<String, T> getRedisTemplate() {
    return redisTemplate;
}

public void setRedisTemplate(RedisTemplate<String, T> redisTemplate) {
    this.redisTemplate = redisTemplate;
}

Now I added data in redisServer like this

public void putData(String uniqueKey, String key, Object results) {

    redisTemplate.opsForHash().put(uniqueKey, key, results);
}

Now i want to remove Expire key.

I search in Google, But in google all are saying like this

redisTemplate.expire(key, timeout, TimeUnit);

In this expire method, We need to provide uniqueKey instead of key. But I need to Expire key instead of uniqueKey.

So Please help me what can i do for expire Key?

How to get Key & Value both from RedisFuture while using RedisAsyncCommands in Lettuce

$
0
0

How to get Key & Value both from RedisFuture while using RedisAsyncCommands in Lettuce.

RedisClient redisClient = RedisClient .create("redis://localhost:6379/");
StatefulRedisConnection<String, String> connection = redisClient.connect();
RedisAsyncCommands<String, String> commands = connection.async();

// disable auto-flushing
commands.setAutoFlushCommands(false);

List<RedisFuture<?>> futures = new ArrayList<>();
for (int i = 0; i < 10; i++) {
    futures.add(commands.get("key-" + i));
}

commands.flushCommands();

for(RedisFuture future : futures) {
    System.out.println(future.get()); //Giving only values.
}
connection.close();

So my expectation is I need the key object as well along with value from RedisFuture object. This is because in my real example, there can be a possibility that there will be no value for a specific key so i need to have information that for which keys i got the data from cache and so i can create a map out of it.

Please ignore my typos & grammar mistakes.

Subscribe to redis channel (pubsub) using lettuce reactive commands

$
0
0

I am using the io.lettuce.core library and I am having trouble subscribing to a channel using the RedisPubSubReactiveCommands interface.

I have a StatefulRedisPubSubConnection and an active redis cluster which I am attempting to subscribe to.

connection.sync().subscribe("channel") works fine, as does connection.async().subscribe("channel"). However, when I use the reactive 'hot observable' interface provided by lettuce like so:

connection.reactive().subscribe(channels).subscribe();
connection.reactive().observeChannels().doOnNext(this::notifyObservers).subscribe();

It will not register as a subscription action on redis. I feel like I'm following the example given in the lettuce documentation closely.

I'm programming for an interface that accepts a hot Flux Observable and I'm getting close to wrapping the sync or async connection interfaces with my own reactive wrapper and throwing them in the pipe. What am I doing wrong here?

Share Spring Session with Redis Database

$
0
0

Following scenario:

DESCRIPTION:

I develop two microservices with Spring. One Service is the auth service and generates the session. The other service is the ui-service which needs to know if a requesting client is authorized. After some reading I found out that sharing the session with redis seems to be a good solution. (Correct me if there is a better way ) For the coding I followed the example here

Status quo: My auth service works and generates a session in redis:

For example:

127.0.0.1:6379> keys *
1) "spring:session:sessions:a4c11990-94a4-4b99-bc77-33f2084e5e8f"
2) "spring:session:sessions:expires:a4c11990-94a4-4b99-bc77-33f2084e5e8f"
3) "spring:session:sessions:26f24541-74dd-4410-84ac-d051a64d1263"
4) "spring:session:index:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME:userA"
5) "spring:session:expirations:1557314160000"
6) "spring:session:sessions:expires:26f24541-74dd-4410-84ac-d051a64d1263"

Now I want to call a test endpoint of my ui service. This call should be successfull if the session is valid and access denied when there is no valid session. Atm I always get an access denied error in my ui service.

Code: My auth service:

application.properties

spring.session.store-type=redis
spring.session.redis.flush-mode=on-save
spring.session.redis.namespace=spring:session
spring.redis.host=localhost
spring.redis.port=6379

pom.xml

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session</artifactId>
            <version>1.3.5.RELEASE</version>
        </dependency>

SessionConfig

@Configuration
@EnableRedisHttpSession
public class SessionConfig extends AbstractHttpSessionApplicationInitializer {
      @Bean
        public JedisConnectionFactory jedisConnectionFactory() {
            return new JedisConnectionFactory();
        }
@Bean
public HttpSessionIdResolver httpSessionIdResolver() {
    CookieHttpSessionIdResolver resolver = new CookieHttpSessionIdResolver();
    DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
    cookieSerializer.setUseBase64Encoding(false);
    resolver.setCookieSerializer(cookieSerializer);
    return resolver; 
}

and in my main class I did

@EnableRedisHttpSession

And in my UI Service:

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.4.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.test</groupId>
    <artifactId>Redistest</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>Redistest</name>
    <description>Microservice for Data Management</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>


                <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>

            <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session</artifactId>
            <version>1.3.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

main:

@EnableWebSecurity
@SpringBootApplication
public class RedistestApplication {

    public static void main(String[] args) {
        SpringApplication.run(RedistestApplication.class, args);
    }

SessionConfig:

@Configuration
@EnableRedisHttpSession
public class SessionConfig extends AbstractHttpSessionApplicationInitializer {
      @Bean
        public JedisConnectionFactory jedisConnectionFactory() {
            return new JedisConnectionFactory();
            }
 @Bean
    public HttpSessionIdResolver httpSessionIdResolver() {
        return HeaderHttpSessionIdResolver.xAuthToken(); 
    }

WebSecurity:

@Configuration
public class WebSecurity extends WebSecurityConfigurerAdapter{

     @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .authorizeRequests()
                    .anyRequest().authenticated();
        }
}

}

Controller

@RestController
public class TestController {

    @GetMapping("/name")
    public String getName() {
        return "Hallo From Test";
    }

}

QUESTION: I'm not getting any error in my services. It seems like I just can't use the session from reddis. In the tutorial the author says that there might be a problem with the base64 encoding of the session-id in the cookie. I guess this might be the problem. Do you have any suggestion or see any error in my implementation? Do I have to disable the HttpSession exlipcitly? Thank's for your help/hints.

EDIT: I just recognized that in my browser Inspect (Firefox) i'm not having any "x-auth" field. My intention is to save the auth id (Session-id) in the header not as a cookie. So I expect that my auth service should set the sessionid as x-auth field in the header. Is that correct? So the error seems to come from the auth service?


How we can access the same cache between two war files?

$
0
0

I am using @Cacheable of Spring annotation to cache the data and Redis as the cache manager.

I created the cache with name xyx on one war, now I want to access/update/delete the same cache on another war.

Below is the code I have used to create the cache manager

@Bean
  public JedisConnectionFactory redisConnectionFactory() {
    JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory();

    // Defaults
    redisConnectionFactory.setHostName("127.0.0.1");
    redisConnectionFactory.setPort(6379);
    return redisConnectionFactory;
  }

Bean
  public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory cf) {
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
    redisTemplate.setConnectionFactory(cf);
    return redisTemplate;
  }

@Primary
  @Bean(name = "cManager")
  public CacheManager cacheManager(RedisTemplate redisTemplate) {
    RedisCacheManager cm= new RedisCacheManager(redisTemplate);
    return cm;
  }

Below is the method to cache the data in war 1

@Cacheable(value = "xyz"  , cacheManager = "cManager")
public Map<String, Map<String, List<DTO>>> cachingData()
        throws CustomException {
    //logic
    }

Spring Data and Redis - serializing transient fields

$
0
0

I am using Redis as my database with Spring data, with no custom value or hash value serializer. I assume the standrad JdkSerializationRedisSerializer should be used then for objects serialization. It looks like transient fields of some objects are serialized to the database.

Transient field modifier, transient method annotations, @JsonIgnore properties - all of them don't seem to affect the serialization of the field.

How can I overcome this issue?

Lettuce RedisCodec For Numbers

$
0
0

Using Lettuce 5 as a Redis client for the first time - I'm finding it rather confusing to simply create a RedisCommands<String, Long> for getting/setting Redis values as a Long. It's a little unclear to me how I can accomplish this. From what I gather, the simplest way is to use the RedisClient overloaded constructor which takes a RedisCodec and RedisURI, but it seems I also need to implement the codec decoding/encoding methods? Since storing numbers is a fairly common use case with Redis, I find this approach rather bloated and I'm suprised there is no predefined codec for integer/long. Given this, I suspect there may be a simpler alternative that I have not come across. Is there an alternate approach?

How can i find the list of nodes in a redis cluster?

$
0
0

I have created a redis cluster client as follows:

// create uri
RedisURI redisURI = RedisClusterURIUtil.toRedisURI(URI.create("redis://localhost:6379"));

RedisClusterClient redisClusterClient = RedisClusterClient.create(redisURI);

StatefulRedisClusterConnection<String, String> connection = redisClusterClient.connect();

Now as the connection will discover all the nodes in the redis cluster ...

How can i find list of all nodes that my cluster client has discovered ? Is there any method that is available

VS Code not able to resolve Springframework Data Redis related dependencies, however, project builds completely fine in Eclipse

$
0
0

I am using VS Code to compile and debug my Spring Boot Java project with help of Gradle. I recently added Redis dependency to my project. The project compiles in Eclipse, but throws error in VS Code.

enter image description here

enter image description here

Viewing all 2217 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>