Подтвердить что ты не робот

"ПРЕДУПРЕЖДЕНИЕ conda.gateways.disk: exp_backoff_fn (47): Неисправность с ошибкой 41" во время "установки конда"

Начиная с сегодняшнего дня я получаю много

ПРЕДУПРЕЖДЕНИЕ conda.gateways.disk: exp_backoff_fn (47): Неисправность с ошибкой 41

когда я пытаюсь обновить или установить пакеты с помощью conda install или conda update. Например:

(...) C:\Users\...> conda install numba
Fetching package metadata ...........
Solving package specifications: .

Package plan for installation in environment C:\...:

The following packages will be DOWNGRADED due to dependency conflicts:

    numba: 0.30.0-np111py35_0 --> 0.30.1-np111py35_0

Proceed ([y]/n)? y

numba-0.30.0-np111p35_0 100% |###############################| Time: 0:00:00   2.50 MB/s
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41
WARNING conda.gateways.disk:exp_backoff_fn(47): Uncaught backoff with errno 41

Пакеты устанавливаются впоследствии, но все эти предупреждения, похоже, указывают на то, что что-то не работает должным образом.

OS: Windows 10 64 bit
conda: 4.3.4

Не могли бы вы сказать, что мне нужно сделать, чтобы исправить эти предупреждения? Или я могу игнорировать их?

4b9b3361

Ответ 1

Эти предупреждения, которые вы видите, являются "нормальными" в соответствии с текущим деревом источника conda. Чтобы понять происхождение вышеупомянутых предупреждений, давайте посмотрим на исходный код в вопросах и недавнюю фиксацию в репозитории conda (https://github.com/conda/conda). Соответствующий исходный код, который печатает предупреждения, которые вы видите, следующий:

https://github.com/conda/conda/blob/4.3.4/conda/gateways/disk/ init.py

# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function, unicode_literals

import sys
from errno import EACCES, ENOENT, EPERM, EPROTOTYPE
from logging import getLogger
from os.path import basename
from time import sleep

from ...common.compat import on_win

log = getLogger(__name__)

MAX_TRIES = 7


def exp_backoff_fn(fn, *args, **kwargs):
    """Mostly for retrying file operations that fail on Windows due to virus scanners"""
    max_tries = kwargs.pop('max_tries', MAX_TRIES)
    if not on_win:
        return fn(*args, **kwargs)

    import random
    # with max_tries = 6, max total time ~= 3.2 sec
    # with max_tries = 7, max total time ~= 6.5 sec
    for n in range(max_tries):
        try:
            result = fn(*args, **kwargs)
        except (OSError, IOError) as e:
            log.trace(repr(e))
            if e.errno in (EPERM, EACCES):
                if n == max_tries-1:
                    raise
                sleep_time = ((2 ** n) + random.random()) * 0.1
                caller_frame = sys._getframe(1)
                log.trace("retrying %s/%s %s() in %g sec",
                          basename(caller_frame.f_code.co_filename),
                          caller_frame.f_lineno,
                          fn.__name__,
                          sleep_time)
                sleep(sleep_time)
            elif e.errno in (ENOENT, EPROTOTYPE):
                # errno.ENOENT File not found error / No such file or directory
                # errno.EPROTOTYPE OSError(41, 'The directory is not empty')
                raise
            else:
                log.warn("Uncaught backoff with errno %d", e.errno)
                raise
        else:
            return result

Из приведенного выше исходного кода это предупреждение, которое появляется в Windows, которое может появиться, когда

повторное выполнение файловых операций, которые не выполняются в Windows из-за вирусных сканеров

Переходя к особенностям с помощью https://msdn.microsoft.com/en-us/library/t3ayayh1.aspx, кажется, что errno 41 соответствует

ENOTEMPTY: каталог не пуст

который сигнализирует, что указанный каталог не пуст. Это непрозрачная ошибка, потому что у них нет ветки, которая имеет дело с такой ошибкой (ENOTEMPTY), в то время как, например, у них есть другая ошибка, например, EPERM или EACCES.
В commit https://github.com/conda/conda/commit/fb2a783d9b9371559b5ea82aaf8ae631c2ce0450#diff-3757ed9862260ae3b54768b3e482e3fe
они явно удаляют отчетность EPROTOTYPE как OSError(41, 'The directory is not empty'), поэтому теперь вы видите, что номер ошибки, сообщенный как предупреждение в

log.warn("Uncaught backoff with errno %d", e.errno)

Другая часть, которую они изменяют, находится в https://github.com/conda/conda/blob/fb2a783d9b9371559b5ea82aaf8ae631c2ce0450/conda/gateways/disk/delete.py в функции delete_trash(), поэтому теперь, если вы включите информационный журнал, скорее всего, вы увидите строку типа

"Невозможно полностью очистить каталог мусора% s\nУдаются% d оставшихся файлов."

включен

log.info("Unable to fully clean trash directory %s\nThere are %d remaining file(s).",
                 trash_dir, len(files_remaining))  

Теперь delete_trash() вызывается обе вашими командами, которые вы цитируете (установите, обновите):
https://github.com/conda/conda/blob/f4b386476307e3979679957292d4f6e4c581df03/conda/cli/main_install.py
https://github.com/conda/conda/blob/a26b1eff17dcaf12f03aea5bbe8dee1e01308de7/conda/cli/main_update.py

Как видно, delete_trash() запускается соответственно в файлах 'install' и 'update', которые ранее упоминались соответственно следующими фрагментами кода:

from ..gateways.disk.delete import delete_trash

# some other code ...

def execute(args, parser):
    install(args, parser, 'install')
    delete_trash()

и

from ..gateways.disk.delete import delete_trash

# some other code ...

def execute(args, parser):
    install(args, parser, 'update')
    delete_trash()  

delete_trash() затем запускает этот путь кода через backoff_rmdir() или backoff_unlink(), что в конечном итоге приведет к предупреждению, которое вы видите из exp_backoff_fn(), как показано выше.
Итак, чтобы подвести итог, основная цепочка вызовов будет

update or install --> delete_trash() --> backoff_rmdir() or backoff_unlink() --> exp_backoff_fn() --> your warning message

В соответствии с изменениями исходного кода, внесенными в репозиторий, разработчики полагают, что они предупреждают о том, что вы можете спокойно игнорировать, поскольку эти предупреждения происходят на этапе "очистки" команд обновления или установки, то есть после операции обновления или установки успешно выполнены.
Я не мог сказать 100%, что вы можете смело игнорировать эти предупреждения. Если после нескольких попыток команда удалять каталог мусора завершается успешно, тогда проблем нет. Но если это не удастся, вы столкнетесь с проблемой, что этот каталог будет становиться все больше и больше в результате не удалять его. Было несколько выпусков, открытых в репо для этого, и я не знаю, покрывают ли исправления код, который вы нажмете. Мое впечатление, что это не так. Чтобы получить дополнительную информацию, вы можете активировать уровень информационного журнала.


ОБНОВЛЕНИЕ: этот вопрос https://github.com/conda/conda/issues/4164 точно упоминает предупреждения, о которых вы сообщали, потому что люди получали длительное обновление и время установки из-за всех попыток. Поскольку я упоминал, что после всех попыток (экспоненциальных отступлений) операция удаления может быть успешной или неудачной, этот человек также упоминает этот аспект в своем отчете.
Как вы можете видеть здесь
https://github.com/conda/conda/issues/3664
есть несколько хаков, которые люди используют для решения проблемы длительных ожиданий из-за повторных попыток, а также будет выполнять следующий запуск вашей команды conda install X или conda update X без предупреждения. Эти предложения:

  • (для ускорения повтора/удаления) установите MAX_TRIES = 1 в свою копию conda/gateways/disk/ init. py
  • удалите каталог .trash, прежде чем запускать следующий conda install X или conda update X. См. https://github.com/conda/conda/issues/3664 для обходного пути, используемого некоторыми людьми для автоматизации удаления этого каталога с использованием простых скриптов. Это должно быть безопасно для этого.

Таким образом, ответы на ваши вопросы будут следующими:
1) Вы можете использовать обходное решение, упомянутое в https://github.com/conda/conda/issues/3664, в котором используется следующая powershell script (и другая script):

$cir = conda info --root
$trash_dir = "$($cir)\pkgs\.trash"
if (Test-Path $trash_dir){
    Remove-Item -Recurse -Force $trash_dir
}
conda --debug update --all --yes --quiet 

чтобы очистить этот .trash-каталог;

2) Вы можете смело игнорировать предупреждения в том смысле, что они не будут влиять на функциональность; проблема в том, что чем больше .trash будет заселено, тем больше времени и повторов будет продолжаться, чтобы удалить элементы, чтобы вы столкнулись с проблемами производительности; как вы упомянули, что это "утечка", но это не влияет на функциональность. Этот каталог должен быть опустошен и удален, так как он содержит мусор, который больше не нужен. Система попытается удалить его, но, возможно, не сможет этого сделать. Поэтому используйте 1).


ОБНОВЛЕНИЕ 2. Как упоминалось в одном из моих комментариев, одно из ключевых изменений находится в файле conda/gateways/disk/__init__.py, который был "исправлением" (https://github.com/conda/conda/commit/6cb3be39aec1c738678ae27b3a264941d08c859a), что привело к 4.3.6 версии conda (conda 4.3.6 информация о выпуске), который решает данное предупреждение.
Ключевым моментом в том, чтобы не видеть это предупреждение, является наличие ветки, которая явно улавливает и обрабатывает описанную ранее ошибку. Теперь, когда произойдет ошибка типа ENOTEMPTY (которая является ошибкой, вызвавшей печать предупреждения в этом случае), это будет поймано и не пойдет в ветку, которая печатает предупреждение, изученное вопросом. Чтобы понять основные отличия, в версии 4.3.4 это было

elif e.errno in (ENOENT, EPROTOTYPE):                   
     raise
else:
     log.warn("Uncaught backoff with errno %d", e.errno)
     raise

а в версии 4.3.6 это стало:

elif e.errno in (ENOENT, ENOTEMPTY):    
    raise
else:
    log.warn("Uncaught backoff with errno %s %d", errorcode[e.errno], e.errno)
    raise

и вы ясно видите, что теперь эта ошибка не войдет в ветвь else, поэтому вы не увидите это сообщение в этом случае.

Ответ 2

Эти предупреждения уже присутствовали на моем компьютере с версиями 4.3.4 и 4.3.5 с conda, но не в версии 4.2.x, а не в последней версии (4.3.6).

Я думаю, лучший способ "исправить" проблему - это обновить конду:

$ conda update conda

или перейти на 4.2:

$ conda install conda=4.2

В обеих версиях предупреждения исчезают.