Skip to content

Commit

Permalink
Merge pull request #5606 from gitcoinco/kevin/mint_token_requests_in_…
Browse files Browse the repository at this point in the history
…celery

mint kudos token requests (and redeem bulk kudos) in celery via a queue with retries, not on request/response cycle
  • Loading branch information
octavioamu authored Dec 18, 2019
2 parents 0d5efae + 1dbf036 commit be9263e
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 56 deletions.
17 changes: 7 additions & 10 deletions app/kudos/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,18 @@ class TokenRequestAdmin(admin.ModelAdmin):
readonly_fields = ['preview']

def response_change(self, request, obj):

if "_mint_kudos" in request.POST:
tx_id = obj.mint()
self.message_user(request, f"Mint submitted to chain: tx {tx_id}. Once this tx clears pls 'sync kudos'.")
from kudos.tasks import mint_token_request
try:
mint_token_request.delay(obj.id)
self.message_user(request, f"Mint/sync submitted to chain")
except Exception as e:
self.message_user(request, str(e))

if "_change_owner" in request.POST:
obj.to_address = '0x6239FF1040E412491557a7a02b2CBcC5aE85dc8F'
obj.save()
self.message_user(request, f"Changed owner to gitcoin")
if "_sync_kudos" in request.POST:
from kudos.management.commands.mint_all_kudos import sync_latest
sync_latest(0)
sync_latest(1)
sync_latest(2)
sync_latest(3)
self.message_user(request, f"Synced latest 3 kudos from open sea. If there is a new kudos on chain it will appear in the marketplace")
return super().response_change(request, obj)

def preview(self, instance):
Expand Down
3 changes: 3 additions & 0 deletions app/kudos/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,9 @@ def __str__(self):
"""Return the string representation of a model."""
return f"Token: {self.token} num_uses_total: {self.num_uses_total}"

def get_absolute_url(self):
return settings.BASE_URL + f"kudos/redeem/{self.secret}"

@property
def url(self):
return f"/kudos/redeem/{self.secret}"
Expand Down
58 changes: 58 additions & 0 deletions app/kudos/tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import time

from app.redis_service import RedisService
from celery import app
from celery.utils.log import get_task_logger
from dashboard.utils import get_web3
from hexbytes import HexBytes
from kudos.models import KudosTransfer, TokenRequest

logger = get_task_logger(__name__)

redis = RedisService().redis

# Lock timeout of 2 minutes (just in the case that the application hangs to avoid a redis deadlock)
LOCK_TIMEOUT = 60 * 2


@app.shared_task(bind=True, max_retries=3)
def mint_token_request(self, token_req_id, retry=False):
"""
:param self:
:param token_req_id:
:return:
"""
with redis.lock("tasks:token_req_id:%s" % token_req_id, timeout=LOCK_TIMEOUT):
from kudos.management.commands.mint_all_kudos import sync_latest
from dashboard.utils import has_tx_mined
obj = TokenRequest.objects.get(pk=token_req_id)
tx_id = obj.mint()
if tx_id:
while not has_tx_mined(tx_id, obj.network):
time.sleep(1)
sync_latest(0)
sync_latest(1)
sync_latest(2)
sync_latest(3)
else:
self.retry(30)


@app.shared_task(bind=True, max_retries=3)
def redeem_bulk_kudos(self, kt_id, signed_rawTransaction, retry=False):
"""
:param self:
:param kt_id:
:param signed_rawTransaction:
:return:
"""
with redis.lock("tasks:redeem_bulk_kudos:%s" % kt_id, timeout=LOCK_TIMEOUT):
try:
obj = KudosTransfer.objects.get(pk=kt_id)
w3 = get_web3(obj.network)
obj.txid = w3.eth.sendRawTransaction(HexBytes(signed_rawTransaction)).hex()
obj.receive_txid = obj.txid
obj.save()
pass
except Exception as e:
self.retry(30)
8 changes: 7 additions & 1 deletion app/kudos/templates/transaction/receive_bulk.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,13 @@
<header class="text-center">
<div id="receove_eth_done" class="text-center" {% if not kudos_transfer.receive_txid %} style="display:none;" {%endif%}>
<h1>{% trans "Congrats!" %} 🎉</h1>
<p>You've received a "{{ coupon.token.humanized_name }}" Kudos via transaction <a href="https://etherscan.io/tx/{{kudos_transfer.receive_txid}}"><span id="trans_id">{{kudos_transfer.receive_txid}}</span></a>.</p>
<p>You've received a "{{ coupon.token.humanized_name }}" Kudos
{% if kudos_transfer.receive_txid != 'pending_celery' %}
via transaction <a href="https://etherscan.io/tx/{{kudos_transfer.receive_txid}}"><span id="trans_id">{{kudos_transfer.receive_txid}}</span></a>
{% else %}
{% endif %}

.</p>
<p>{% trans "You can see your kudos in any web3 wallet that supports ERC-721-compliant NFTs, or in your" %} <a href="{% url 'profile' %}">Gitcoin {% trans "profile" %}</a>.</p>
{% include 'shared/twitter.html' %}
<p>
Expand Down
8 changes: 6 additions & 2 deletions app/kudos/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,8 +380,12 @@ def _get_contract(self):
obj: Web3py contract object.
"""
with open('kudos/Kudos.json') as f:
abi = json.load(f)
try:
with open('kudos/Kudos.json') as f:
abi = json.load(f)
except:
with open('app/kudos/Kudos.json') as f:
abi = json.load(f)
address = self._get_contract_address()
return self._w3.eth.contract(address=address, abi=abi)

Expand Down
83 changes: 43 additions & 40 deletions app/kudos/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -665,53 +665,56 @@ def redeem_bulk_coupon(coupon, profile, address, ip_address, save_addr=False):
else:

signed = w3.eth.account.signTransaction(tx, private_key)
retry_later = False
try:
txid = w3.eth.sendRawTransaction(signed.rawTransaction).hex()
except Exception as e:
txid = "pending_celery"
retry_later = True

with transaction.atomic():
kudos_transfer = KudosTransfer.objects.create(
emails=[profile.email],
# For kudos, `token` is a kudos.models.Token instance.
kudos_token_cloned_from=coupon.token,
amount=coupon.token.price_in_eth,
comments_public=coupon.comments_to_put_in_kudos_transfer,
ip=ip_address,
github_url='',
from_name=coupon.sender_profile.handle,
from_email='',
from_username=coupon.sender_profile.handle,
username=profile.handle,
network=coupon.token.contract.network,
from_address=kudos_owner_address,
is_for_bounty_fulfiller=False,
metadata={'coupon_redemption': True, 'nonce': nonce},
recipient_profile=profile,
sender_profile=coupon.sender_profile,
txid=txid,
receive_txid=txid,
tx_status='pending',
receive_tx_status='pending',
)

with transaction.atomic():
kudos_transfer = KudosTransfer.objects.create(
emails=[profile.email],
# For kudos, `token` is a kudos.models.Token instance.
kudos_token_cloned_from=coupon.token,
amount=coupon.token.price_in_eth,
comments_public=coupon.comments_to_put_in_kudos_transfer,
ip=ip_address,
github_url='',
from_name=coupon.sender_profile.handle,
from_email='',
from_username=coupon.sender_profile.handle,
username=profile.handle,
network=coupon.token.contract.network,
from_address=kudos_owner_address,
is_for_bounty_fulfiller=False,
metadata={'coupon_redemption': True, 'nonce': nonce},
recipient_profile=profile,
sender_profile=coupon.sender_profile,
txid=txid,
receive_txid=txid,
tx_status='pending',
receive_tx_status='pending',
# save to DB
BulkTransferRedemption.objects.create(
coupon=coupon,
redeemed_by=profile,
ip_address=ip_address,
kudostransfer=kudos_transfer,
)

# save to DB
BulkTransferRedemption.objects.create(
coupon=coupon,
redeemed_by=profile,
ip_address=ip_address,
kudostransfer=kudos_transfer,
)
coupon.num_uses_remaining -= 1
coupon.current_uses += 1
coupon.save()

coupon.num_uses_remaining -= 1
coupon.current_uses += 1
coupon.save()
# send email
maybe_market_kudos_to_email(kudos_transfer)

# send email
maybe_market_kudos_to_email(kudos_transfer)
except Exception as e:
error = "Could not redeem your kudos. Please try again soon."
if "replacement transaction underpriced" in str(e):
error = "There is already an airdrop transfer in progress. Please try again in a minute or two.. (note: in the future we will add 'queue'-ing so you dont have to resubmit, as soon as this ticket (https://github.com/gitcoinco/web/issues/4976) is deployed)"
return None, error, None
if retry_later:
from kudos.tasks import redeem_bulk_kudos
redeem_bulk_kudos.delay(kudos_transfer.id, signed.rawTransaction.hex())

return True, None, kudos_transfer

Expand Down
3 changes: 1 addition & 2 deletions app/retail/templates/admin/change_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@
<input type="submit" value="Impersonate" name="_impersonate" value="1">
<input type="submit" value="Recalculate Profile Frontend" name="_recalc_flontend" value="1">
{% elif 'kudos/tokenrequest' in request.build_absolute_uri %}
<input type="submit" value="Mint Kudos" name="_mint_kudos" value="1">
<input type="submit" value="Mint + Sync Kudos" name="_mint_kudos" value="1">
<input type="submit" value="Change Owner to Gitcoin" name="_change_owner" value="1">
<input type="submit" value="Sync Kudos" name="_sync_kudos" value="1">
{% elif 'quests/quest' in request.build_absolute_uri %}
<input type="submit" value="Approve Request" name="_approve_quest" value="1">
{% endif %}
Expand Down
2 changes: 1 addition & 1 deletion scripts/restore_backup.bash
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
END

apk --update add postgresql-client
apt-get install postgresql-client -f

if [ "$2" == "1" ]; then
echo "DROP SCHEMA public CASCADE;
Expand Down

0 comments on commit be9263e

Please sign in to comment.