Open idealatom opened 9 years ago
Does the warning actually have those %s
s in it? You should see a message with those replaced with the actual storage and filenames.
As for that warning, it's telling you that the storage backend decided to use a different file name. This will happen if the name is not available. Generally, this shouldn't happen, but it can be caused by multiple simultaneous attempts to generate the same image.
The IOError seems like maybe you're missing source files.
If you could create a reduced test case, that would make it a lot easier to help out.
Does the warning actually have those %ss in it?
Of course no. I get various messages with different filenames. And I don't understand why it's happens. Could you describe what can cause the possible situation with multiple simultaneous attempts to generate the same image?
For example I get warning _"The storage backend did not save the file with the requested name ("/path-to-thumbnails/A.jpg") and instead used "/path-to-thumbnails/Adfge.jpg". When I look in directory "/path-to-thumbnails/" I see both equal images A.jpg and _Adfge.jpg.
The IOError seems like maybe you're missing source files.
No, the missing path in this error is a thumbnail path, not a source file. For example I get error "No such file or directory: /path-to-thumbnails/B.jpg'" But right after that, when I checking existence of B.jpg, it's already exists and error with this filename doesn't repeat anymore when I refresh page. It looks like sometimes a thumbnail doesn't have time to generate during first request and it generating after. That is why I get IOError and that is why missing file is existed when I check it.
If you could create a reduced test case, that would make it a lot easier to help out.
I would be glad to do it, but this warning and mistakes not always occur. I do not know how to cause them. They happens randomly 2-4 times in a day only on production server.
What is your IMAGEKIT_DEFAULT_CACHEFILE_STRATEGY in settings? By default it's 'imagekit.cachefiles.strategies.JustInTime' - images generated when u access url/width/height attr on it.
ImageField in Django forms first save record to db and then save file to destination folder, so u have a short period of time when record to image in db, but file does not exist on disk.
Simple solution to your case:
1) Ignore this errors (bad solution, u have 500 error)
2) Set IMAGEKIT_DEFAULT_CACHEFILE_STRATEGY = 'imagekit.cachefiles.strategies.Optimistic'
in settings
3) or modify your function
def make_thumbnail(source, width, height, generator_id=None):
if not os.path.exist(source):
return None
...
and use tags someting like
{% if component.to_product.get_image|file_exist %}
{% generateimage 'plumbing:product_thumb' source=component.to_product.get_image as thumb %}
<img src="{{ thumb.url }}" width="{{ thumb.width }}" height="{{ thumb.height}}">
{% endif %}
and add file_exist function to templates https://docs.djangoproject.com/en/1.7/howto/custom-template-tags/#writing-custom-template-filters
def file_exist(value): # Only one argument.
return os.path.exist(value)
@nex2hex, thanks for your reply.
What is your IMAGEKIT_DEFAULT_CACHEFILE_STRATEGY in settings?
I don't set imagekit cachefile strategy in my settings.
I try your 2nd and 3rd solutions and report the results.
Could you describe what can cause the possible situation with multiple simultaneous attempts to generate the same image?
Doing anything that generates the image ({% generateimage %}
, file.generate()
, file.url
, etc) while it's already being generated. There's no lock so it will simply attempt to save the file twice. After the first file is written, the storage backend will use a different filename for the second.
It looks like sometimes a thumbnail doesn't have time to generate during first request and it generating after. That is why I get IOError and that is why missing file is existed when I check it.
The default strategy generates the file synchronously as part of the request/response cycle so this isn't possible AFAIK.
Are you getting the warnings on the same files as the errors? Also, are you doing anything that would cause additional asynchronicity?
Are you getting the warnings on the same files as the errors?
No, as I can see, files from warning and errors are different.
Also, are you doing anything that would cause additional asynchronicity?
No. I don't have any complicated environment. Every settings for imagekit are default, except CACHEFILE_NAMER, I use source_name_dot_hash.
I made additional research and found some new details. All thumbnail files from warning and errors have same size 82x82. I found in my code 2 places where I create thumbnails with a size of 82 pixels. In all of this places I use function make_thumbnail, so likely the problem in this function:
# plumbing/images.py
from imagekit.cachefiles import ImageCacheFile
from imagekit.registry import generator_registry
from imagekit.templatetags.imagekit import DEFAULT_THUMBNAIL_GENERATOR
def make_thumbnail(source, width, height, generator_id=None):
if generator_id is None:
generator_id = DEFAULT_THUMBNAIL_GENERATOR
kwargs = {
'source': source,
'width': width,
'height': height,
}
generator = generator_registry.get(generator_id, **kwargs)
return ImageCacheFile(generator)
First piece of code: I create thumbnails in 2 inline admin classes:
# admin.py
from plumbing.images import make_thumbnail
class OrderItemInline(admin.TabularInline):
def get_product_image(obj):
p = obj.product
if p:
thumb = make_thumbnail(p.image_original, 82, 82)
return '<a href="%s"><img src="%s"/></a>' % (get_admin_change_url(p), thumb.url)
get_product_image.allow_tags = True
get_product_image.short_description = u'Изображение'
model = OrderItem
fields = (
get_product_image,
'product',
'price',
'render_count',
'full_price',
'items',
'get_portion',
'count_available',
'is_available'
)
readonly_fields = (
get_product_image,
'full_price',
'render_count',
'get_portion'
)
class PlumbingOrderItemInline(admin.TabularInline):
def product_image(obj):
thumb = make_thumbnail(obj.product.get_image(), 82, 82)
return '<a href="%s"><img src="%s"/></a>' % (get_admin_change_url(obj.product), thumb.url)
product_image.allow_tags = True
product_image.short_description = u'Изображение'
model = PlumbingOrderItem
fields = (
product_image,
'product',
'price',
'quantity',
)
readonly_fields = (product_image, )
Second piece of code: I create thumbnails in my view and set some css styles for them. Maybe the problem here is that I getting height and width in one line of code?
image = make_thumbnail(it.get_image(), 82, 82)
style = 'style="margin: %dpx %dpx"' % ((82 - image.height) / 2, (82 - image.width) / 2)
data.append({
'type': "product",
'url': it.get_absolute_url(),
'image': image.url,
'name': it.full_name,
'producer_name': it.collection.producer.name,
'collection_name': it.collection.name,
'product_type': it.category.name,
'style': style,
})
Force call of os.path.exist(source)
will help you in this case
@nex2hex, I add call of os.path.exist() in make_thumbnail function. Lets see if it works.
same bug for me...
btw i'm still stuck with this issue)
@idealatom looks like with JIT strategy it works. IMAGEKIT_DEFAULT_CACHEFILE_STRATEGY = 'imagekit.cachefiles.strategies.JustInTime'
@alternativshik but I already have this strategy enabled, since it is default strategy and I don't set it directly in settings
@idealatom yep... You'r right. Error still present...
IMAGEKIT_DEFAULT_CACHEFILE_STRATEGY = 'imagekit.cachefiles.strategies.Optimistic'
@nex2hex No. Same errors, but more often.
@nex2hex btw, latest imagekit && latest django 1.8.4, and ImageSpecField with ResizeToFit processor. It can't find CACHE files, but after reload page thumbs are present
show me your model and stacktrace please
@nex2hex https://dpaste.de/xisN and error IOError: [Errno 2] No such file or directory: u'MY_PATH_HERE/project/media/CACHE/images/posts/2013/12/30/f4bb8e11add347d8af517767140433d8/56afdff16f5716e0af37a19de9bfab25.jpg'
MY_PATH_HERE - it's just path to my project folder
@idealatom LOL. Я 3дплитку когда-то в году 12 переделывал импортилки товаров из экселя.
@alternativshik =)) то-то я смотрю, ник знакомый - в истории коммитов мелькал)
Раз уж перешли на русский, отвечу подробнее
Ошибка IOError возникает примерно в таком случае
Создание нового объекта в товаре | Поведение пользователя на сайте |
---|---|
1 Вызов метода save() у объекта: | ... |
1.1 выполнение запроса sql insert | ... |
1.2 ... | пользователь загружает страницу и новый объект попадает в вывод |
1.3 ... | при рендеринге страницы идет обращение к картинке, которая еще не сохранена на диск |
1.4 ... | возникновение IOError |
1.5 выполнение процессоров у ProcessedImageField | ... |
1.6 сохранение картинки на диск | ... |
Т.е. между выполнением запроса и появлением картинки на диске проходит значительное количество времени.
Решение этой проблемы я описал тут https://github.com/matthewwithanm/django-imagekit/issues/315#issuecomment-85433129
Если ставите стратегию IMAGEKIT_DEFAULT_CACHEFILE_STRATEGY = 'imagekit.cachefiles.strategies.Optimistic' - то создание всех превьюшек будет происходить при сохранении объекта. Если не исопльзовать в выводе полечение ширины и высоты превьюшек (а только вызов thumbnail.url ) , то при стратегии Optimistic ошибок не будет, она в этом случае не дергает метод _generate() (получение width и height дергают каждый раз и не кэшируют размеры - старайтесь не пользоваться ими).
При переключении на Optimistic надо пройти по всем ранее созданным превьюшкам и сгенерировать у них картинки (JustInTime генерирует при обращении к свойству, а не при сохранении):
for image in images:
image.thumbnail.generate()
image.medium.generate()
из-за того, что этого не сделал - и была куча ошибок
@nex2hex Так, ясно/понятно. Самое странное, что этот косяк вылез конкретно у меня после обновления с какой-то старой версии. До этого данная проблема не наблюдалась. Проблема совсем некритичная в моем случае, скорее немного неприятная) Как быть со старыми изображениями, для которых нет превьюшек, ведь для них они не будут создаваться при стратегии Optimistic? (Вариант перегенерации руками лучше исключить вообще.) Раньше как-то иначе работала генерация?
при оптимистик - только руками, да. И при добавлении нового поля в модель - не забывать перегенерировать тоже.
Если вариант неприемлем, то переключиться на JustInTime и
1) написать враппер для получения урла, который будет ловить эксепшены IOError и не использовать width height (они сильно снижают производительность - открывать картинку и получать ее размеры каждый раз дорого).
2) или переписать метод save у модели, чтобы сначала сохранял картинку на диск, а потом вносил изменения в базу
@nex2hex Спасибо за разъяснение. Можно закрывать.
Hello. I came across a problem with imagekit. I see a lot of warnings in Sentry from _generate method of ImageCacheFile - "The storage backend %s did not save the file with the requested name ("%s") and instead used "%s"". Also I have even more errors "IOError: [Errno 2] No such file or directory:"
This errors raises randomly, on different pages in small percent of requests . And if I reload same page right after error everything will be ok. There is no errors in my local devserver. Looks like some race condition situation. Here is different traceback:
I'm using Imagekit 3.2.4 with Django 1.4.14. This is my imagekit settings: IMAGEKIT_SPEC_CACHEFILE_NAMER = 'imagekit.cachefiles.namers.source_name_dot_hash'
This is my imagegenerators:
Here's how I use its in templates:
Also I have this function for generating thumbnails in views:
I use this function like here, where get_image function returns value of ImageField:
Could you tell me why warnings are happens? What is the possible cause of this warnings and errors?