Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Object update doesn't update document of index in Docker #11

Open
tomsin9 opened this issue Jan 3, 2025 · 11 comments
Open

Object update doesn't update document of index in Docker #11

tomsin9 opened this issue Jan 3, 2025 · 11 comments

Comments

@tomsin9
Copy link

tomsin9 commented Jan 3, 2025

This functionality worked well when running locally without Docker.

I'm facing an issue (only in Docker) with my Django application where updates to the index settings in Meilisearch are successful, but the actual document updates for my Job model are not being updated in the index.

In my settings.py, I have configured Meilisearch HOST to meili's container_name, seems it doesn't accept 'localhost'.

Environment:
Django Version: 4.2
Docker Version: 4.37.1
Meilisearch Version: 0.33.0
Django-Meili Version: 0.0.8

@tomsin9
Copy link
Author

tomsin9 commented Jan 6, 2025

FYI, for my case, syncindex and clearindex also worked well, just the object update doesn't work

@ikollipara
Copy link
Owner

Hi, thanks for submitting an issue request. I have a few questions about your setup, and I would like to see your application code as well.

  1. Is the entire environment within a docker container, as in a docker-compose environment similar to Laravel Sail? Or is it just the meilisearch instance?
  2. If the latter, is meilisearch's port exposed?

I would also like to see your model code and settings code as well. It would help me get a fuller picture of what exactly you're facing.

@tomsin9
Copy link
Author

tomsin9 commented Jan 8, 2025

Thank you for replying.

You are correct, I am using a Docker Compose environment. I currently use signals.py with post_save and pre_delete to update documents instead. Since the create indexes, syncindex, and clearindex functions work well, indicating that Django can connect to MeiliSearch, the issue seems to be that updates to instances have no effect.

and here is my code:

settings.py:

MEILISEARCH = {
    'HTTPS': False, 
    'HOST': 'meilisearch-service', 
    'MASTER_KEY': 'master-key-here', 
    'PORT': 7700,
    'TIMEOUT': None, 
    'CLIENT_AGENTS': None, 
    'DEBUG': DEBUG, 
    'SYNC': False, 
    'OFFLINE': False, 
    'DEFAULT_BATCH_SIZE': 1000,
}

docker-compose.yaml:

services:
  meilisearch-service:
    image: getmeili/meilisearch:v1.12
    ports:
      - 7700:7700
    volumes:
      - ../meili_data:/meili_data
    env_file:
      - .env.meilisearch
    container_name: ges_meili_container

  ges-db:
    image: postgres:16
    volumes:
      - ../postgres-ges-django/data/db:/var/lib/postgresql/data
    env_file:
      - .env.db
    container_name: ges_db_container

  ges-app:
    build: .
    # env_file:
    #   - .env.deploy
    volumes: 
      - ./public/media/:/var/www/ges-django/public/media
      - ./.env.deploy:/var/www/ges-django/.env
    ports: 
      - 8000:8000
    container_name: ges_django_container
    command: sh docker-entrypoint.sh
    depends_on:
      - ges-db
      - meilisearch-service

@ikollipara
Copy link
Owner

Is there anything in the Meilisearch log to indicate a failed updated? I ask because I know the async implementation in Meilisearch can be a pain.

@tomsin9
Copy link
Author

tomsin9 commented Jan 9, 2025

Actually there are no logs generated for instance updates in Meilisearch. Only settings changes are logged when using Django's runserver and the specified commands.

@ikollipara
Copy link
Owner

What happens when you run the program with SYNC set to True? It could be an issue with the async

@tomsin9
Copy link
Author

tomsin9 commented Jan 10, 2025

The same issue persists, seems there is no response from MeiliSearch..

Currently, I am using signals.py to handle this for me, with SYNC = False

from django.db.models.signals import post_save, pre_delete
from django.dispatch import receiver
from django_meili._client import client as _client

def _serialize(model) -> dict:
    """
    Serialize the model instance into a dictionary.
    """
    serialized = model.meili_serialize()
    pk = model.pk
    return serialized | {"id": pk, "pk": pk}

@receiver(post_save, sender=Job)
def update_documents(sender, instance, created, **kwargs):
    """
    Update MeiliSearch index for the instance after save.
    """
    if created:
        task = _client.get_index(sender.__name__).add_documents([_serialize(instance)])
    else:
        task = _client.get_index(sender.__name__).update_documents([_serialize(instance)])

@receiver(pre_delete, sender=Job)
def delete_document(sender, instance, **kwargs):
    """
    Delete MeiliSearch index for the instance before delete.
    """
    _client.get_index(sender.__name__).delete_document(instance.pk)

@ikollipara
Copy link
Owner

Interesting, what does the model definition look like? I assume you're inheriting the correct model, but I'm trying to brainstorm what might be happening. Thank you for being patient.

@tomsin9
Copy link
Author

tomsin9 commented Jan 13, 2025

Thank you for your assistance! Here is the model:

from django.db import models
from django.utils.translation import gettext_lazy as _
from ckeditor.fields import RichTextField
from cities_light.models import Region
from django_meili.models import IndexMixin

EMPLOYMENT_TYPE_CHOICES = [
    ('FULL_TIME', _('Full Time')),
    ('PART_TIME', _('Part Time')),
    ('TEMPORARY', _('Temporary')),
    ('INTERNSHIP', _('Internship')),
]

class Job(IndexMixin, models.Model):
    uid = models.CharField(max_length=12, unique=True, verbose_name=_('UID'))
    company = models.ForeignKey('companies.Company', on_delete=models.CASCADE, verbose_name=_('Company'))
    title = models.CharField(max_length=512, verbose_name=_('Title'))
    employment_type = models.CharField(max_length=36, choices=EMPLOYMENT_TYPE_CHOICES, verbose_name=_('Employment Type'), blank=True, null=True)
    region = models.ForeignKey(Region, on_delete=models.SET_NULL, null=True, blank=True)
    description = models.TextField(verbose_name=_('Job Description'))
    responsibilities = RichTextField(config_name='form', verbose_name=_('Responsibilities'), blank=True, null=True)
    requirements = RichTextField(config_name='form', verbose_name=_('Requirements'), blank=True, null=True)
    job_offer = RichTextField(config_name='form', verbose_name=_('Job Offer'), blank=True, null=True)
    published_at = models.DateTimeField(auto_now_add=True, verbose_name=_('Published At'))
    updated_at = models.DateTimeField(auto_now=True, verbose_name=_('Updated At'))
    status = models.CharField(max_length=16, default='active', verbose_name=_('Status'), choices=(
        ('OPEN', _('Open')),
        ('CLOSED', _('Closed')),
    ))
    
    class Meta:
        verbose_name = _('Job')
        verbose_name_plural = _('Jobs')
        ordering = ('-published_at', '-updated_at')
        
    class MeiliMeta:
        displayed_fields = ('id', 'uid', 'title', 'company', 'employment_type', 'region', 'description', 'published_at', 'updated_at', 'status') 
        searchable_fields = ('title', 'company')
        filterable_fields = ('company', 'employment_type', 'region') 
        sortable_fields = ('published_at', ) 

@ikollipara
Copy link
Owner

I think the issue is related to the RichTextField. Can you add a custom meili_serialize() method that can check for this? My guess is that it's throwing an error that you (and I) aren't seeing.

@tomsin9
Copy link
Author

tomsin9 commented Jan 14, 2025

I implemented a simple meili_serialize(), but it seems that it doesn't work when the instance is updated in the Docker Compose environment. However, it does print the data correctly when I run python manage.py runserver locally.

def meili_serialize(self):
    data = super().meili_serialize()

    data['responsibilities'] = self.responsibilities or ''
    data['requirements'] = self.requirements or ''
    data['job_offer'] = self.job_offer or ''
    
    print("Serialized Data:", data)
    return data

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants