code: def listener(self, channels=None, patterns=None, is_async=False):
          
          def decorator(fn):
              _channels = channels or []
              _patterns = patterns or []
  
              @wraps(fn)
              def inner():
                  pubsub = self.pubsub()
  
                  def listen():
                      for channel in _channels:
                          pubsub.subscribe(channel)
                      for pattern in _patterns:
                          pubsub.psubscribe(pattern)
  
                      for data_dict in pubsub.listen():
                          try:
                              ret = fn(**data_dict)
                          except StopIteration:
                              pubsub.close()
                              break
  
                  if is_async:
                      worker = threading.Thread(target=listen)
                      worker.start()
                      return worker
                  else:
                      listen()
  
              return inner
          return decorator
docs: Decorator for wrapping functions used to listen for Redis
          pub-sub messages.
  
          The listener will listen until the decorated function
          raises a ``StopIteration`` exception.
  
          :param list channels: Channels to listen on.
          :param list patterns: Patterns to match.
          :param bool is_async: Whether to start the listener in a
              separate thread.