Package: websubsub
Django websub subscriber.Installationpip install websubsubAddwebsubsub.apps.WebsubsubConfigto the list ofINSTALLED_APPSin yoursettings.py:INSTALLED_APPS = [
    ...,
    'websubsub.apps.WebsubsubConfig'
]Set theWEBSUBSUB_OWN_ROOTURLsetting in yoursettings.pyto the
full url of your project site, e.g.https://example.com/. It will be
used to build full callback urls.SetDUMBLOCK_REDIS_URLsettings in yoursettings.py. Redis locks
are used to ensure subscription/unsubscription tasks are consistent with
hub and local database.WEBSUBSUB_OWN_ROOTURL = 'http://example.com/'
DUMBLOCK_REDIS_URL= 'redis://redishost:6379'Addwebsubsub.tasks.refresh_subscriptionsandwebsubsub.tasks.retry_failedto celerybeat schedule. If you define
it insettings.py:CELERY_BEAT_SCHEDULE = {
    'websub_refresh': {
        'task': 'websubsub.tasks.refresh_subscriptions',
        'schedule': 3600  # Hourly
    },
    'websub_retry': {
        'task': 'websubsub.tasks.retry_failed',
        'schedule': 600  # Every 10 minutes
    },
}UsageCreate Websub callbackCreate celery task handler, usually intasks.py:from celery import shared_task

@shared_task
def news_task(data):
    print('got news!')Callback url should end with uuid. Register url for handler inurls.py:from websubsub.views import WssView
from .tasks import news_task, reports_task

urlpatterns = [
    path('/websubcallback/news/<uuid:id>', WssView.as_view(news_task), name='webnews')
    path('/websubcallback/reports/<uuid:id>', WssView.as_view(reports_task), name='webreports')
]SubscribeYou can create subscription on the go, or use static subscriptions.To create subscription in the code:from websubsub.models import Subscription
Subscription.create(topic='mytopic', urlname='webnews', hub='http://example.com')This will create Subscription object in the database and schedule celery
task to subscribe with hub.Static subscriptionsStatic subscriptions can be defined in yoursettings.py, they are
then materialized with management command./manage.py websub_static_subscribe.Add static subscriptions in yoursettings.py:WEBSUBSUB_HUBS = {
    'http://example.com': {
        'subscriptions': [
            {'topic': 'mytopic', 'callback_urlname': 'webnews'},
            ...
        ]
    }
}Execute./manage.py websub_static_subscribeUnsubscribeTo unsubscribe existing subscription, callSubscription.unsubscribe()method:from websubsub.models import Subscription
Subscription.objects.get(pk=4).unsubscribe()SettingsWEBSUBSUB_OWN_ROOTURL- ex.:https://example.com/. Required. Will
be used to build full callback urls.DUMBLOCK_REDIS_URL- ex.:redis://redishost:6379. Required. Will
be used to lock atomic tasks.WEBSUBSUB_AUTOFIX_URLS- IfTrue, thenwebsubsub.tasks.subscribe()task will be allowed to ovewrite
subscription.callback_url, resolving its callback_urlname. If False, it
will print an error and exit. Default:TrueWEBSUBSUB_DEFAULT_HUB_URLWEBSUBSUB_MAX_CONNECT_RETRIESWEBSUBSUB_MAX_HUB_ERROR_RETRIESWEBSUBSUB_MAX_VERIFY_RETRIESWEBSUBSUB_VERIFY_WAIT_TIME- How many seconds should pass before
unverified subscription is considered failed. After that time,websubsub.tasks.retry_failed()task will be able to retry
subscription process again.Management commands./manage.py websub_static_subscribe- Materialize static
subscriptions from settings. Optional arguments:--purge-orphans- delete old static subscriptions from database-y,--yes- answer yes to all--reset-counters- reset retry counters--force- send new subscription request to hub even if already
subscribed or explicitly unsubscribed./manage.py websub_purge_unresolvable- Delete all subscriptions
with unresolvable urlname from database../manage.py websub_purge_all- Delete all subscriptions from
database../manage.py websub_reset_counters- Reset retry counters for all
subscriptions in database../manage.py websub_handle_url_changes- Guess changed urlnames for
subscriptions from current callback_url. Also detect changed url
patterns and schedule resubscribe with new url../manage.py dumpdata websubsub--indent2- Show all subscriptions.Testingpip install -r tests/requirements.txt
py.test