على GitLab CI، صورة php:8.3-cli، مشروع فيه نحو 140 حزمة Composer وملف composer.lock ثابت لم يتغير بين التشغيلين. البناء الأول استغرق 3 دقائق و10 ثوانٍ، والثاني 6 دقائق و40 ثانية، والثالث 3 دقائق. لا تغيير في الكود ولا في الـlock. الظاهرة تكررت أسبوعين قبل أن أفتحها.
الخطوة الأولى كانت تثبيت المتغيرات بدل التخمين:
composer install --no-interaction --prefer-dist --no-progress -vvv 2>&1 | ts '%H:%M:%.S'
مع COMPOSER_CACHE_DIR=/tmp/composer-cache داخل الحاوية وcache:key في CI مربوطًا ببصمة composer.lock. الفرق ظهر في سطر واحد: التشغيل البطيء كان يعيد تنزيل الحزم من dist بدل أخذها من الكاش، لأن مسار الكاش كان داخل /tmp ويُمسح مع كل وظيفة جديدة.
نقلت الكاش إلى مسار داخل مساحة العمل يُحفظ بين الوظائف:
variables:
COMPOSER_CACHE_DIR: "$CI_PROJECT_DIR/.composer-cache"
cache:
key: composer-$CI_COMMIT_REF_SLUG
paths:
- .composer-cache/
بعد ذلك صار الوقت ثابتًا تقريبًا عند 3 دقائق. لكن هذا وحده لم يكن كافيًا، لأن composer install ما زال يتحقق من الشبكة. أضفت --no-scripts في مرحلة التثبيت ونقلت السكربتات إلى خطوة منفصلة، فانخفض الوقت دقيقة أخرى، مقابل أن أي سكربت يفشل لن يوقف التثبيت نفسه؛ هذا مقبول عندي لأن الخطوة التالية تفشل بوضوح.
السبب الميكانيكي بسيط: Composer يخزّن أرشيفات dist في الكاش، لكنه يعيد التحقق من composer.lock ومن صلاحية الروابط. إذا كان الكاش باردًا، كل حزمة تُنزّل من جديد. وإذا كان دافئًا لكن الـlock تغيّر، يعيد كل شيء تقريبًا. لهذا ربط cache:key ببصمة الملف أهم من حجم الكاش.
ما يخالف هذا: تشغيل composer update في CI، أو الاعتماد على composer install بدون lock في المستودع، أو مشاركة كاش واحد بين فروع كثيرة. جربت مشاركة الكاش بين كل الفروع، فبدأت وظائف قديمة تسحب حزمًا لا تخصها وتفشل بصمت في التحقق. أيضًا على runners بمساحة قرص صغيرة، كاش Composer ينمو بسرعة ويسبب فشلًا في منتصف البناء؛ حددت --no-cache لبعض الوظائف القصيرة بدل مطاردة المساحة.
الحد الذي لم أحسمه بعد: هل الأفضل كاش مشترك بمفتاح ثابت مع composer validate صارم، أم كاش لكل فرع كما فعلت؟ الأول أسرع عند أول بناء لفرع جديد، والثاني أقل مفاجآت. ما الذي استقر عندك في مشروع فيه فروع كثيرة ونشر متكرر؟


0 条评论
还没有评论,写下第一条。