2015-01-23 3 views
1

У меня есть простое приложение ниже. Я отключу ведение журнала запросов в Laravel, я отключу, где это возможно, но эта функция будет обрабатывать только около 800 записей, прежде чем я выйду из ОЗУ на моем 2GB Linode. Я знаю, что я прошу многих из вас, ребята, но я не могу видеть, где я пропадаю память.Почему у моего приложения заканчивается память? Отмена переменных, используя chunk

Есть действительно только два основных шага.

Шаг 1 - Перемещение записей из временной таблицы для производства

class ListingMigrator 
{ 
    public function __construct($tempListing, $feed) 
    { 
     $this->tempListing = $tempListing; 
     $this->listing = $this->listingInstance(); 
     $this->feed = $feed; 
    } 

    public static function migrateListing($listing, $feed) 
    { 
     $instance = new static($listing, $feed); 
     return $instance->migrate(); 
    } 

    public function migrate() 
    { 
     $this->addExternalData(); 
     $this->populateListing(); 
     $this->processPhotos(); 
     $this->deleteTempListing(); 
    } 

    private function listingInstance() 
    { 
     DB::connection()->disableQueryLog(); 
     $listing = Listing::findByMud($this->tempListing->matrix_unique_id); 
     return $listing ?: new Listing; 
    } 

    private function processPhotos() 
    { 
     $retsApi = new RetsFeedApi($this->feed); 
     /* Initialize Object */ 
     $rets = $retsApi->findMostRecent(); 
     $photos = $rets->getPhotosForListing($this->listing->matrix_unique_id); 
         foreach ($photos as $photo) 
         { 
          $uploader = new PhotoProcessor($this->listing, $photo); 
          $uploader->process(); 
         } 
    } 

    private function populateListing() 
    { 
     DB::connection()->disableQueryLog(); 
     $this->listing->fill($this->tempListing->toArray()); 
     $this->listing->imported_at = $this->tempListing->created_at; 
     $this->listing->board = $this->tempListing->board; 

     return $this->listing->save(); 
    } 

    private function addExternalData() 
    { 
     // Get Google lattitude and longitude 
     $googlecoords = getGoogleMapInfo($this->tempListing->FullAddress, $this->tempListing->City); 
     $this->listing->GoogleLat = $googlecoords['GoogleLat']; 
     $this->listing->GoogleLong = $googlecoords['GoogleLong']; 

     // Add or update the Subdivision Table (helper function) 
     $subdivisiondata = SubdivisionUpdate($this->tempListing->board, $this->tempListing->SubCondoName, $this->tempListing->Development); 
     $this->listing->SubdivisionID = $subdivisiondata['id']; 
    } 

    private function deleteTempListing() 
    { 
     return $this->tempListing->delete(); 
    } 
} 

Шаг 2 - Загрузить фотографии и выкладывание на Amazon S3

class PhotoProcessor 
{ 
    public function __construct(Listing $listing, $photoData) 
    { 
    $this->bucket  = 'real-estate-listings'; 
    $this->s3   = App::make('aws')->get('s3'); 
    $this->tempFileName = 'app/storage/processing/images/retsphotoupload'; 
    $this->photoData = $photoData; 
    $this->listing  = $listing; 
    $this->photo  = new RetsPhoto; 
    } 

    public function process() 
    { 
    $this->storeTempFile(); 
    $this->storeFileInfo(); 
    $this->buildPhoto(); 

    $success = $this->pushToS3(); 

    // if Result has the full URL or you want to build it, add it to $this->photo 
    DB::connection()->disableQueryLog(); 
    $this->listing->photos()->save($this->photo); 
    $this->removeTempFile(); 
    unset ($this->photoData); 
    return $success; 
    } 

    private function storeTempFile() 
    { 
    return File::put($this->tempFileName, $this->photoData['Data']) > 0; 
    } 

    private function storeFileInfo() 
    { 
    $fileInfo = getimagesize($this->tempFileName); 
    // Could even be its own object 
    $this->fileInfo = [ 
    'width'  => $fileInfo[0], 
    'height' => $fileInfo[1], 
    'mimetype' => $fileInfo['mime'], 
    'extension' => $this->getFileExtension($fileInfo['mime']) 
    ]; 
    } 

    private function buildPhoto() 
    { 
    $this->photo->number = $this->photoData['Object-ID']; // Storing this because it is relevant order wise 
    $this->photo->width = $this->fileInfo['width']; 
    $this->photo->height = $this->fileInfo['height']; 
    $this->photo->path = $this->getFilePath(); 
    } 

    private function getFilePath() 
    { 
    $path = []; 
    if ($this->listing->City == NULL) 
    { 
     $path[] = Str::slug('No City'); 
    } 
    else 
    { 
     $path[] = Str::slug($this->listing->City, $separator = '-'); 
    } 

    if ($this->listing->Development == NULL) 
    { 
     $path[] = Str::slug('No Development'); 
    } 
    else 
    { 
     $path[] = Str::slug($this->listing->Development, $separator = '-'); 
    } 

    if ($this->listing->Subdivision == NULL) 
    { 
     $pathp[] = Str::slug('No Subdivision'); 
    } 
    else 
    { 
     $path[] = Str::slug($this->listing->Subdivision, $separator = '-'); 
    } 

    if ($this->listing->MLSNumber == NULL) 
    { 
     $pathp[] = Str::slug('No MLSNumber'); 
    } 
    else 
    { 
     $path[] = Str::slug($this->listing->MLSNumber, $separator = '-'); 
    } 

     $path[] = $this->photoData['Object-ID'].'.'.$this->fileInfo['extension']; 

     return strtolower(join('/', $path)); 
    } 

    private function pushToS3() 
    { 
    return $this->s3->putObject([ 
     'Bucket'  => $this->bucket, 
     'Key'  => $this->photo->path, 
     'ContentType'=> $this->fileInfo['mimetype'], 
     'SourceFile' => $this->tempFileName 
    ]); 
    } 

    private function getFileExtension($mime) 
    { 
    // Use better algorithm than this 
    $ext = str_replace('image/', '', $mime); 
    return $ext == 'jpeg' ? 'jpg' : $ext; 
    } 

    private function removeTempFile() 
    { 
    return File::delete($this->tempFileName); 
    } 
} 

Редактировать показать RetsPhoto

class RetsPhoto extends Eloquent { 

    protected $table = 'rets_property_photos'; 

    public function listing() { 

     return $this->belongsTo('Listing', 'matrix_unique_id', 'matrix_unique_id'); 
    } 

} 

Edit # 2: Chunk Вызов Это в приложение/команды и единственное, что там есть функция огня() ниже:

public function fire() 
{ 
    // Turn off query logging 
    DB::connection()->disableQueryLog(); 

    $feeds = RetsFeed::where('active','=',1)->get(); 
    foreach ($feeds as $feed) 
    { 

     $class = "TempListing{$feed->board}"; 

     $listings = $class::orderBy('MatrixModifiedDT','desc'); 

     $listings->chunk(50, function($listings) use($feed) { 
      $listings->each(function($listing) use ($feed) { 
       ListingMigrator::migrateListing($listing,$feed); 
       echo "Feed: $feed->board\r\n"; 
       echo "SubcondoName: $listing->SubCondoName\r\n"; 
       echo "Development: $listing->Development\r\n"; 
       echo "\r\n"; 
      }); 
     }); 
    } 

} 
+1

У меня есть ощущение, что 'getimagesize' загружает ресурс в память. – Marty

+0

@ Marty, как бы я сказал? –

+0

Я пытаюсь выяснить наверняка на данный момент, а также как освободить эту память. – Marty

ответ

1

Я думаю, что я понял это.

  1. Ваша система хранит в памяти все данные фотографии. Как засвидетельствовано unset ($ this-> photoData);

    1. Проблема в том, что вам нужно сначала выполнить функцию процесса. Ваше приложение вряд ли обрабатывает ЛЮБЫЕ фотографии, поэтому, когда вы продолжаете хватать их из файловой системы, у вас заканчивается память, прежде чем вы даже обрабатываете один.

Чтобы подтвердить это, просто возьмите 1 файл не используя метод куска. Я не очень знакомый с Laravel, это может одновременно захватывать все файлы и есть баран.

Вы можете выполнить некоторую трассировку с помощью memory_get_usage (true), чтобы узнать, где именно находится баран. Я бы предложил сначала проанализировать метод пожара.

+0

Не знаю. Он загружает все фотографии для одной записи в таблице темп и переносит эту одну запись на главную таблицу, загружая и повторно загружая изображения на S3, а затем двигается дальше. Он загружает изображения по одному. –

Смежные вопросы