Exemplo n.º 1
0
def update_config_cache(generate, organization_id=None, project_id=None, update_reason=None):
    """
    Update the Redis cache for the Relay projectconfig. This task is invoked
    whenever a project/org option has been saved or smart quotas potentially
    caused a change in projectconfig.

    Either organization_id or project_id has to be provided.

    :param organization_id: The organization for which to invalidate configs.
    :param project_id: The project for which to invalidate configs.
    :param generate: If `True`, caches will be eagerly regenerated, not only
        invalidated.
    """

    from sentry.models import Project
    from sentry.relay import projectconfig_cache
    from sentry.relay.config import get_project_config

    # Delete key before generating configs such that we never have an outdated
    # but valid cache.
    #
    # If this was running at the end of the task, it would be more effective
    # against bursts of updates, but introduces a different race where an
    # outdated cache may be used.
    debounce_key = _get_schedule_debounce_key(project_id, organization_id)
    cache.delete(debounce_key)

    if project_id:
        projects = [Project.objects.get_from_cache(id=project_id)]
    elif organization_id:
        # XXX(markus): I feel like we should be able to cache this but I don't
        # want to add another method to src/sentry/db/models/manager.py
        projects = Project.objects.filter(organization_id=organization_id)

    if generate:
        project_keys = {}
        for key in ProjectKey.objects.filter(project_id__in=[project.id for project in projects]):
            project_keys.setdefault(key.project_id, []).append(key)

        project_configs = {}
        for project in projects:
            project_config = get_project_config(
                project, project_keys=project_keys.get(project.id, []), full_config=True
            )
            project_configs[project.id] = project_config.to_dict()

        projectconfig_cache.set_many(project_configs)
    else:
        projectconfig_cache.delete_many([project.id for project in projects])

    metrics.incr(
        "relay.projectconfig_cache.done",
        tags={"generate": generate, "update_reason": update_reason},
    )
Exemplo n.º 2
0
def update_config_cache(generate,
                        organization_id=None,
                        project_id=None,
                        public_key=None,
                        update_reason=None):
    """
    Update the Redis cache for the Relay projectconfig. This task is invoked
    whenever a project/org option has been saved or smart quotas potentially
    caused a change in projectconfig.

    Either organization_id or project_id has to be provided.

    :param organization_id: The organization for which to invalidate configs.
    :param project_id: The project for which to invalidate configs.
    :param generate: If `True`, caches will be eagerly regenerated, not only
        invalidated.
    """

    from sentry.models import Project, ProjectKey, ProjectKeyStatus
    from sentry.relay import projectconfig_cache
    from sentry.relay.config import get_project_config

    if project_id:
        set_current_event_project(project_id)

    if organization_id:
        # Cannot use bind_organization_context here because we do not have a
        # model and don't want to fetch one
        sentry_sdk.set_tag("organization_id", organization_id)

    if public_key:
        sentry_sdk.set_tag("public_key", public_key)

    sentry_sdk.set_tag("update_reason", update_reason)
    sentry_sdk.set_tag("generate", generate)

    # Delete key before generating configs such that we never have an outdated
    # but valid cache.
    #
    # If this was running at the end of the task, it would be more effective
    # against bursts of updates, but introduces a different race where an
    # outdated cache may be used.
    projectconfig_debounce_cache.mark_task_done(public_key, project_id,
                                                organization_id)

    if organization_id:
        projects = list(
            Project.objects.filter(organization_id=organization_id))
        keys = list(ProjectKey.objects.filter(project__in=projects))
    elif project_id:
        projects = [Project.objects.get(id=project_id)]
        keys = list(ProjectKey.objects.filter(project__in=projects))
    elif public_key:
        try:
            keys = [ProjectKey.objects.get(public_key=public_key)]
        except ProjectKey.DoesNotExist:
            # In this particular case, where a project key got deleted and
            # triggered an update, we at least know the public key that needs
            # to be deleted from cache.
            #
            # In other similar cases, like an org being deleted, we potentially
            # cannot find any keys anymore, so we don't know which cache keys
            # to delete.
            projectconfig_cache.delete_many([public_key])
            return

    else:
        assert False

    if generate:
        config_cache = {}
        for key in keys:
            if key.status != ProjectKeyStatus.ACTIVE:
                project_config = {"disabled": True}
            else:
                project_config = get_project_config(
                    key.project, project_keys=[key],
                    full_config=True).to_dict()
            config_cache[key.public_key] = project_config

        projectconfig_cache.set_many(config_cache)
    else:
        cache_keys_to_delete = []
        for key in keys:
            cache_keys_to_delete.append(key.public_key)

        projectconfig_cache.delete_many(cache_keys_to_delete)
Exemplo n.º 3
0
def update_config_cache(generate,
                        organization_id=None,
                        project_id=None,
                        update_reason=None):
    """
    Update the Redis cache for the Relay projectconfig. This task is invoked
    whenever a project/org option has been saved or smart quotas potentially
    caused a change in projectconfig.

    Either organization_id or project_id has to be provided.

    :param organization_id: The organization for which to invalidate configs.
    :param project_id: The project for which to invalidate configs.
    :param generate: If `True`, caches will be eagerly regenerated, not only
        invalidated.
    """

    from sentry.models import Project, ProjectKey, ProjectKeyStatus
    from sentry.relay import projectconfig_cache
    from sentry.relay.config import get_project_config

    if project_id:
        set_current_event_project(project_id)

    if organization_id:
        # Cannot use bind_organization_context here because we do not have a
        # model and don't want to fetch one
        sentry_sdk.set_tag("organization_id", organization_id)

    sentry_sdk.set_tag("update_reason", update_reason)
    sentry_sdk.set_tag("generate", generate)

    # Delete key before generating configs such that we never have an outdated
    # but valid cache.
    #
    # If this was running at the end of the task, it would be more effective
    # against bursts of updates, but introduces a different race where an
    # outdated cache may be used.
    projectconfig_debounce_cache.mark_task_done(project_id, organization_id)

    if project_id:
        projects = [Project.objects.get_from_cache(id=project_id)]
    elif organization_id:
        # XXX(markus): I feel like we should be able to cache this but I don't
        # want to add another method to src/sentry/db/models/manager.py
        projects = Project.objects.filter(organization_id=organization_id)

    project_keys = {}
    for key in ProjectKey.objects.filter(
            project_id__in=[project.id for project in projects]):
        project_keys.setdefault(key.project_id, []).append(key)

    if generate:
        config_cache = {}
        for project in projects:
            project_config = get_project_config(project,
                                                project_keys=project_keys.get(
                                                    project.id, []),
                                                full_config=True)
            config_cache[project.id] = project_config.to_dict()

            for key in project_keys.get(project.id) or ():
                # XXX(markus): This is currently the cleanest way to get only
                # state for a single projectkey (considering quotas and
                # everything)
                if key.status != ProjectKeyStatus.ACTIVE:
                    continue

                project_config = get_project_config(project,
                                                    project_keys=[key],
                                                    full_config=True)
                config_cache[key.public_key] = project_config.to_dict()

        projectconfig_cache.set_many(config_cache)
    else:
        cache_keys_to_delete = []
        for project in projects:
            cache_keys_to_delete.append(project.id)
            for key in project_keys.get(project.id) or ():
                cache_keys_to_delete.append(key.public_key)

        projectconfig_cache.delete_many(cache_keys_to_delete)

    metrics.incr(
        "relay.projectconfig_cache.done",
        tags={
            "generate": generate,
            "update_reason": update_reason
        },
    )